Updating server dependancies. Also adding github.com/jaytaylor/html2text and gopkg.in/gomail.v2 (#5748)
119
vendor/golang.org/x/crypto/acme/acme.go
сгенерированный
поставляемый
@@ -47,6 +47,10 @@ const LetsEncryptURL = "https://acme-v01.api.letsencrypt.org/directory"
|
||||
const (
|
||||
maxChainLen = 5 // max depth and breadth of a certificate chain
|
||||
maxCertSize = 1 << 20 // max size of a certificate, in bytes
|
||||
|
||||
// Max number of collected nonces kept in memory.
|
||||
// Expect usual peak of 1 or 2.
|
||||
maxNonces = 100
|
||||
)
|
||||
|
||||
// CertOption is an optional argument type for Client methods which manipulate
|
||||
@@ -108,6 +112,9 @@ type Client struct {
|
||||
|
||||
dirMu sync.Mutex // guards writes to dir
|
||||
dir *Directory // cached result of Client's Discover method
|
||||
|
||||
noncesMu sync.Mutex
|
||||
nonces map[string]struct{} // nonces collected from previous responses
|
||||
}
|
||||
|
||||
// Discover performs ACME server discovery using c.DirectoryURL.
|
||||
@@ -131,6 +138,7 @@ func (c *Client) Discover(ctx context.Context) (Directory, error) {
|
||||
return Directory{}, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
c.addNonce(res.Header)
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return Directory{}, responseError(res)
|
||||
}
|
||||
@@ -192,7 +200,7 @@ func (c *Client) CreateCert(ctx context.Context, csr []byte, exp time.Duration,
|
||||
req.NotAfter = now.Add(exp).Format(time.RFC3339)
|
||||
}
|
||||
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, c.dir.CertURL, req)
|
||||
res, err := c.postJWS(ctx, c.Key, c.dir.CertURL, req)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -267,7 +275,7 @@ func (c *Client) RevokeCert(ctx context.Context, key crypto.Signer, cert []byte,
|
||||
if key == nil {
|
||||
key = c.Key
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, key, c.dir.RevokeURL, body)
|
||||
res, err := c.postJWS(ctx, key, c.dir.RevokeURL, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -355,7 +363,7 @@ func (c *Client) Authorize(ctx context.Context, domain string) (*Authorization,
|
||||
Resource: "new-authz",
|
||||
Identifier: authzID{Type: "dns", Value: domain},
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, c.dir.AuthzURL, req)
|
||||
res, err := c.postJWS(ctx, c.Key, c.dir.AuthzURL, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -413,7 +421,7 @@ func (c *Client) RevokeAuthorization(ctx context.Context, url string) error {
|
||||
Status: "deactivated",
|
||||
Delete: true,
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req)
|
||||
res, err := c.postJWS(ctx, c.Key, url, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -519,7 +527,7 @@ func (c *Client) Accept(ctx context.Context, chal *Challenge) (*Challenge, error
|
||||
Type: chal.Type,
|
||||
Auth: auth,
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, chal.URI, req)
|
||||
res, err := c.postJWS(ctx, c.Key, chal.URI, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -652,7 +660,7 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
||||
req.Contact = acct.Contact
|
||||
req.Agreement = acct.AgreedTerms
|
||||
}
|
||||
res, err := postJWS(ctx, c.HTTPClient, c.Key, url, req)
|
||||
res, err := c.postJWS(ctx, c.Key, url, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -689,6 +697,78 @@ func (c *Client) doReg(ctx context.Context, url string, typ string, acct *Accoun
|
||||
}, nil
|
||||
}
|
||||
|
||||
// postJWS signs the body with the given key and POSTs it to the provided url.
|
||||
// The body argument must be JSON-serializable.
|
||||
func (c *Client) postJWS(ctx context.Context, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
|
||||
nonce, err := c.popNonce(ctx, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := jwsEncodeJSON(body, key, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res, err := ctxhttp.Post(ctx, c.HTTPClient, url, "application/jose+json", bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.addNonce(res.Header)
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// popNonce returns a nonce value previously stored with c.addNonce
|
||||
// or fetches a fresh one from the given URL.
|
||||
func (c *Client) popNonce(ctx context.Context, url string) (string, error) {
|
||||
c.noncesMu.Lock()
|
||||
defer c.noncesMu.Unlock()
|
||||
if len(c.nonces) == 0 {
|
||||
return fetchNonce(ctx, c.HTTPClient, url)
|
||||
}
|
||||
var nonce string
|
||||
for nonce = range c.nonces {
|
||||
delete(c.nonces, nonce)
|
||||
break
|
||||
}
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
// addNonce stores a nonce value found in h (if any) for future use.
|
||||
func (c *Client) addNonce(h http.Header) {
|
||||
v := nonceFromHeader(h)
|
||||
if v == "" {
|
||||
return
|
||||
}
|
||||
c.noncesMu.Lock()
|
||||
defer c.noncesMu.Unlock()
|
||||
if len(c.nonces) >= maxNonces {
|
||||
return
|
||||
}
|
||||
if c.nonces == nil {
|
||||
c.nonces = make(map[string]struct{})
|
||||
}
|
||||
c.nonces[v] = struct{}{}
|
||||
}
|
||||
|
||||
func fetchNonce(ctx context.Context, client *http.Client, url string) (string, error) {
|
||||
resp, err := ctxhttp.Head(ctx, client, url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
nonce := nonceFromHeader(resp.Header)
|
||||
if nonce == "" {
|
||||
if resp.StatusCode > 299 {
|
||||
return "", responseError(resp)
|
||||
}
|
||||
return "", errors.New("acme: nonce not found")
|
||||
}
|
||||
return nonce, nil
|
||||
}
|
||||
|
||||
func nonceFromHeader(h http.Header) string {
|
||||
return h.Get("Replay-Nonce")
|
||||
}
|
||||
|
||||
func responseCert(ctx context.Context, client *http.Client, res *http.Response, bundle bool) ([][]byte, error) {
|
||||
b, err := ioutil.ReadAll(io.LimitReader(res.Body, maxCertSize+1))
|
||||
if err != nil {
|
||||
@@ -793,33 +873,6 @@ func chainCert(ctx context.Context, client *http.Client, url string, depth int)
|
||||
return chain, nil
|
||||
}
|
||||
|
||||
// postJWS signs the body with the given key and POSTs it to the provided url.
|
||||
// The body argument must be JSON-serializable.
|
||||
func postJWS(ctx context.Context, client *http.Client, key crypto.Signer, url string, body interface{}) (*http.Response, error) {
|
||||
nonce, err := fetchNonce(ctx, client, url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := jwsEncodeJSON(body, key, nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ctxhttp.Post(ctx, client, url, "application/jose+json", bytes.NewReader(b))
|
||||
}
|
||||
|
||||
func fetchNonce(ctx context.Context, client *http.Client, url string) (string, error) {
|
||||
resp, err := ctxhttp.Head(ctx, client, url)
|
||||
if err != nil {
|
||||
return "", nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
enc := resp.Header.Get("replay-nonce")
|
||||
if enc == "" {
|
||||
return "", errors.New("acme: nonce not found")
|
||||
}
|
||||
return enc, nil
|
||||
}
|
||||
|
||||
// linkHeader returns URI-Reference values of all Link headers
|
||||
// with relation-type rel.
|
||||
// See https://tools.ietf.org/html/rfc5988#section-5 for details.
|
||||
|
||||
117
vendor/golang.org/x/crypto/acme/acme_test.go
сгенерированный
поставляемый
@@ -45,6 +45,28 @@ func decodeJWSRequest(t *testing.T, v interface{}, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
type jwsHead struct {
|
||||
Alg string
|
||||
Nonce string
|
||||
JWK map[string]string `json:"jwk"`
|
||||
}
|
||||
|
||||
func decodeJWSHead(r *http.Request) (*jwsHead, error) {
|
||||
var req struct{ Protected string }
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := base64.RawURLEncoding.DecodeString(req.Protected)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var head jwsHead
|
||||
if err := json.Unmarshal(b, &head); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &head, nil
|
||||
}
|
||||
|
||||
func TestDiscover(t *testing.T) {
|
||||
const (
|
||||
reg = "https://example.com/acme/new-reg"
|
||||
@@ -916,7 +938,30 @@ func TestRevokeCert(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchNonce(t *testing.T) {
|
||||
func TestNonce_add(t *testing.T) {
|
||||
var c Client
|
||||
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||
c.addNonce(http.Header{"Replay-Nonce": {}})
|
||||
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||
|
||||
nonces := map[string]struct{}{"nonce": struct{}{}}
|
||||
if !reflect.DeepEqual(c.nonces, nonces) {
|
||||
t.Errorf("c.nonces = %q; want %q", c.nonces, nonces)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_addMax(t *testing.T) {
|
||||
c := &Client{nonces: make(map[string]struct{})}
|
||||
for i := 0; i < maxNonces; i++ {
|
||||
c.nonces[fmt.Sprintf("%d", i)] = struct{}{}
|
||||
}
|
||||
c.addNonce(http.Header{"Replay-Nonce": {"nonce"}})
|
||||
if n := len(c.nonces); n != maxNonces {
|
||||
t.Errorf("len(c.nonces) = %d; want %d", n, maxNonces)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_fetch(t *testing.T) {
|
||||
tests := []struct {
|
||||
code int
|
||||
nonce string
|
||||
@@ -949,6 +994,76 @@ func TestFetchNonce(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_fetchError(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusTooManyRequests)
|
||||
}))
|
||||
defer ts.Close()
|
||||
_, err := fetchNonce(context.Background(), http.DefaultClient, ts.URL)
|
||||
e, ok := err.(*Error)
|
||||
if !ok {
|
||||
t.Fatalf("err is %T; want *Error", err)
|
||||
}
|
||||
if e.StatusCode != http.StatusTooManyRequests {
|
||||
t.Errorf("e.StatusCode = %d; want %d", e.StatusCode, http.StatusTooManyRequests)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNonce_postJWS(t *testing.T) {
|
||||
var count int
|
||||
seen := make(map[string]bool)
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
w.Header().Set("replay-nonce", fmt.Sprintf("nonce%d", count))
|
||||
if r.Method == "HEAD" {
|
||||
// We expect the client do a HEAD request
|
||||
// but only to fetch the first nonce.
|
||||
return
|
||||
}
|
||||
// Make client.Authorize happy; we're not testing its result.
|
||||
defer func() {
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
w.Write([]byte(`{"status":"valid"}`))
|
||||
}()
|
||||
|
||||
head, err := decodeJWSHead(r)
|
||||
if err != nil {
|
||||
t.Errorf("decodeJWSHead: %v", err)
|
||||
return
|
||||
}
|
||||
if head.Nonce == "" {
|
||||
t.Error("head.Nonce is empty")
|
||||
return
|
||||
}
|
||||
if seen[head.Nonce] {
|
||||
t.Errorf("nonce is already used: %q", head.Nonce)
|
||||
}
|
||||
seen[head.Nonce] = true
|
||||
}))
|
||||
defer ts.Close()
|
||||
|
||||
client := Client{Key: testKey, dir: &Directory{AuthzURL: ts.URL}}
|
||||
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||
t.Errorf("client.Authorize 1: %v", err)
|
||||
}
|
||||
// The second call should not generate another extra HEAD request.
|
||||
if _, err := client.Authorize(context.Background(), "example.com"); err != nil {
|
||||
t.Errorf("client.Authorize 2: %v", err)
|
||||
}
|
||||
|
||||
if count != 3 {
|
||||
t.Errorf("total requests count: %d; want 3", count)
|
||||
}
|
||||
if n := len(client.nonces); n != 1 {
|
||||
t.Errorf("len(client.nonces) = %d; want 1", n)
|
||||
}
|
||||
for k := range seen {
|
||||
if _, exist := client.nonces[k]; exist {
|
||||
t.Errorf("used nonce %q in client.nonces", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkHeader(t *testing.T) {
|
||||
h := http.Header{"Link": {
|
||||
`<https://example.com/acme/new-authz>;rel="next"`,
|
||||
|
||||
41
vendor/golang.org/x/crypto/acme/autocert/autocert_test.go
сгенерированный
поставляемый
@@ -22,6 +22,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -51,26 +52,44 @@ var authzTmpl = template.Must(template.New("authz").Parse(`{
|
||||
]
|
||||
}`))
|
||||
|
||||
type memCache map[string][]byte
|
||||
type memCache struct {
|
||||
mu sync.Mutex
|
||||
keyData map[string][]byte
|
||||
}
|
||||
|
||||
func (m memCache) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
v, ok := m[key]
|
||||
func (m *memCache) Get(ctx context.Context, key string) ([]byte, error) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
v, ok := m.keyData[key]
|
||||
if !ok {
|
||||
return nil, ErrCacheMiss
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (m memCache) Put(ctx context.Context, key string, data []byte) error {
|
||||
m[key] = data
|
||||
func (m *memCache) Put(ctx context.Context, key string, data []byte) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
m.keyData[key] = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m memCache) Delete(ctx context.Context, key string) error {
|
||||
delete(m, key)
|
||||
func (m *memCache) Delete(ctx context.Context, key string) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
delete(m.keyData, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
func newMemCache() *memCache {
|
||||
return &memCache{
|
||||
keyData: make(map[string][]byte),
|
||||
}
|
||||
}
|
||||
|
||||
func dummyCert(pub interface{}, san ...string) ([]byte, error) {
|
||||
return dateDummyCert(pub, time.Now(), time.Now().Add(90*24*time.Hour), san...)
|
||||
}
|
||||
@@ -124,7 +143,7 @@ func TestGetCertificate_trailingDot(t *testing.T) {
|
||||
func TestGetCertificate_ForceRSA(t *testing.T) {
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Cache: make(memCache),
|
||||
Cache: newMemCache(),
|
||||
ForceRSA: true,
|
||||
}
|
||||
defer man.stopRenew()
|
||||
@@ -280,8 +299,7 @@ func testGetCertificate(t *testing.T, man *Manager, domain string, hello *tls.Cl
|
||||
}
|
||||
|
||||
func TestAccountKeyCache(t *testing.T) {
|
||||
cache := make(memCache)
|
||||
m := Manager{Cache: cache}
|
||||
m := Manager{Cache: newMemCache()}
|
||||
ctx := context.Background()
|
||||
k1, err := m.accountKey(ctx)
|
||||
if err != nil {
|
||||
@@ -315,8 +333,7 @@ func TestCache(t *testing.T) {
|
||||
PrivateKey: privKey,
|
||||
}
|
||||
|
||||
cache := make(memCache)
|
||||
man := &Manager{Cache: cache}
|
||||
man := &Manager{Cache: newMemCache()}
|
||||
defer man.stopRenew()
|
||||
if err := man.cachePut("example.org", tlscert); err != nil {
|
||||
t.Fatalf("man.cachePut: %v", err)
|
||||
|
||||
2
vendor/golang.org/x/crypto/acme/autocert/renewal_test.go
сгенерированный
поставляемый
@@ -111,7 +111,7 @@ func TestRenewFromCache(t *testing.T) {
|
||||
}
|
||||
man := &Manager{
|
||||
Prompt: AcceptTOS,
|
||||
Cache: make(memCache),
|
||||
Cache: newMemCache(),
|
||||
RenewBefore: 24 * time.Hour,
|
||||
Client: &acme.Client{
|
||||
Key: key,
|
||||
|
||||
688
vendor/golang.org/x/crypto/blake2b/blake2bAVX2_amd64.s
сгенерированный
поставляемый
@@ -54,68 +54,223 @@ DATA ·AVX_c48<>+0x00(SB)/8, $0x0100070605040302
|
||||
DATA ·AVX_c48<>+0x08(SB)/8, $0x09080f0e0d0c0b0a
|
||||
GLOBL ·AVX_c48<>(SB), (NOPTR+RODATA), $16
|
||||
|
||||
// unfortunately the BYTE representation of VPERMQ must be used
|
||||
#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \
|
||||
VPADDQ m0, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFD $-79, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPSHUFB c40, Y1, Y1; \
|
||||
VPADDQ m1, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFB c48, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPADDQ Y1, Y1, t; \
|
||||
VPSRLQ $63, Y1, Y1; \
|
||||
VPXOR t, Y1, Y1; \
|
||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39 \ // VPERMQ 0x39, Y1, Y1
|
||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e \ // VPERMQ 0x4e, Y2, Y2
|
||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93 \ // VPERMQ 0x93, Y3, Y3
|
||||
VPADDQ m2, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFD $-79, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPSHUFB c40, Y1, Y1; \
|
||||
VPADDQ m3, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFB c48, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPADDQ Y1, Y1, t; \
|
||||
VPSRLQ $63, Y1, Y1; \
|
||||
VPXOR t, Y1, Y1; \
|
||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39 \ // VPERMQ 0x39, Y3, Y3
|
||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e \ // VPERMQ 0x4e, Y2, Y2
|
||||
BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93 \ // VPERMQ 0x93, Y1, Y1
|
||||
#define VPERMQ_0x39_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x39
|
||||
#define VPERMQ_0x93_Y1_Y1 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xc9; BYTE $0x93
|
||||
#define VPERMQ_0x4E_Y2_Y2 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xd2; BYTE $0x4e
|
||||
#define VPERMQ_0x93_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x93
|
||||
#define VPERMQ_0x39_Y3_Y3 BYTE $0xc4; BYTE $0xe3; BYTE $0xfd; BYTE $0x00; BYTE $0xdb; BYTE $0x39
|
||||
|
||||
// load msg into Y12, Y13, Y14, Y15
|
||||
#define LOAD_MSG_AVX2(src, i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15) \
|
||||
MOVQ i0*8(src), X12; \
|
||||
PINSRQ $1, i1*8(src), X12; \
|
||||
MOVQ i2*8(src), X11; \
|
||||
PINSRQ $1, i3*8(src), X11; \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
MOVQ i4*8(src), X13; \
|
||||
PINSRQ $1, i5*8(src), X13; \
|
||||
MOVQ i6*8(src), X11; \
|
||||
PINSRQ $1, i7*8(src), X11; \
|
||||
VINSERTI128 $1, X11, Y13, Y13; \
|
||||
MOVQ i8*8(src), X14; \
|
||||
PINSRQ $1, i9*8(src), X14; \
|
||||
MOVQ i10*8(src), X11; \
|
||||
PINSRQ $1, i11*8(src), X11; \
|
||||
#define ROUND_AVX2(m0, m1, m2, m3, t, c40, c48) \
|
||||
VPADDQ m0, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFD $-79, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPSHUFB c40, Y1, Y1; \
|
||||
VPADDQ m1, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFB c48, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPADDQ Y1, Y1, t; \
|
||||
VPSRLQ $63, Y1, Y1; \
|
||||
VPXOR t, Y1, Y1; \
|
||||
VPERMQ_0x39_Y1_Y1; \
|
||||
VPERMQ_0x4E_Y2_Y2; \
|
||||
VPERMQ_0x93_Y3_Y3; \
|
||||
VPADDQ m2, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFD $-79, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPSHUFB c40, Y1, Y1; \
|
||||
VPADDQ m3, Y0, Y0; \
|
||||
VPADDQ Y1, Y0, Y0; \
|
||||
VPXOR Y0, Y3, Y3; \
|
||||
VPSHUFB c48, Y3, Y3; \
|
||||
VPADDQ Y3, Y2, Y2; \
|
||||
VPXOR Y2, Y1, Y1; \
|
||||
VPADDQ Y1, Y1, t; \
|
||||
VPSRLQ $63, Y1, Y1; \
|
||||
VPXOR t, Y1, Y1; \
|
||||
VPERMQ_0x39_Y3_Y3; \
|
||||
VPERMQ_0x4E_Y2_Y2; \
|
||||
VPERMQ_0x93_Y1_Y1
|
||||
|
||||
#define VMOVQ_SI_X11_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x1E
|
||||
#define VMOVQ_SI_X12_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x26
|
||||
#define VMOVQ_SI_X13_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x2E
|
||||
#define VMOVQ_SI_X14_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x36
|
||||
#define VMOVQ_SI_X15_0 BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x3E
|
||||
|
||||
#define VMOVQ_SI_X11(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x5E; BYTE $n
|
||||
#define VMOVQ_SI_X12(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x66; BYTE $n
|
||||
#define VMOVQ_SI_X13(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x6E; BYTE $n
|
||||
#define VMOVQ_SI_X14(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x76; BYTE $n
|
||||
#define VMOVQ_SI_X15(n) BYTE $0xC5; BYTE $0x7A; BYTE $0x7E; BYTE $0x7E; BYTE $n
|
||||
|
||||
#define VPINSRQ_1_SI_X11_0 BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x1E; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X12_0 BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x26; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X13_0 BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x2E; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X14_0 BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x36; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X15_0 BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x3E; BYTE $0x01
|
||||
|
||||
#define VPINSRQ_1_SI_X11(n) BYTE $0xC4; BYTE $0x63; BYTE $0xA1; BYTE $0x22; BYTE $0x5E; BYTE $n; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X12(n) BYTE $0xC4; BYTE $0x63; BYTE $0x99; BYTE $0x22; BYTE $0x66; BYTE $n; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X13(n) BYTE $0xC4; BYTE $0x63; BYTE $0x91; BYTE $0x22; BYTE $0x6E; BYTE $n; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X14(n) BYTE $0xC4; BYTE $0x63; BYTE $0x89; BYTE $0x22; BYTE $0x76; BYTE $n; BYTE $0x01
|
||||
#define VPINSRQ_1_SI_X15(n) BYTE $0xC4; BYTE $0x63; BYTE $0x81; BYTE $0x22; BYTE $0x7E; BYTE $n; BYTE $0x01
|
||||
|
||||
#define VMOVQ_R8_X15 BYTE $0xC4; BYTE $0x41; BYTE $0xF9; BYTE $0x6E; BYTE $0xF8
|
||||
#define VPINSRQ_1_R9_X15 BYTE $0xC4; BYTE $0x43; BYTE $0x81; BYTE $0x22; BYTE $0xF9; BYTE $0x01
|
||||
|
||||
// load msg: Y12 = (i0, i1, i2, i3)
|
||||
// i0, i1, i2, i3 must not be 0
|
||||
#define LOAD_MSG_AVX2_Y12(i0, i1, i2, i3) \
|
||||
VMOVQ_SI_X12(i0*8); \
|
||||
VMOVQ_SI_X11(i2*8); \
|
||||
VPINSRQ_1_SI_X12(i1*8); \
|
||||
VPINSRQ_1_SI_X11(i3*8); \
|
||||
VINSERTI128 $1, X11, Y12, Y12
|
||||
|
||||
// load msg: Y13 = (i0, i1, i2, i3)
|
||||
// i0, i1, i2, i3 must not be 0
|
||||
#define LOAD_MSG_AVX2_Y13(i0, i1, i2, i3) \
|
||||
VMOVQ_SI_X13(i0*8); \
|
||||
VMOVQ_SI_X11(i2*8); \
|
||||
VPINSRQ_1_SI_X13(i1*8); \
|
||||
VPINSRQ_1_SI_X11(i3*8); \
|
||||
VINSERTI128 $1, X11, Y13, Y13
|
||||
|
||||
// load msg: Y14 = (i0, i1, i2, i3)
|
||||
// i0, i1, i2, i3 must not be 0
|
||||
#define LOAD_MSG_AVX2_Y14(i0, i1, i2, i3) \
|
||||
VMOVQ_SI_X14(i0*8); \
|
||||
VMOVQ_SI_X11(i2*8); \
|
||||
VPINSRQ_1_SI_X14(i1*8); \
|
||||
VPINSRQ_1_SI_X11(i3*8); \
|
||||
VINSERTI128 $1, X11, Y14, Y14
|
||||
|
||||
// load msg: Y15 = (i0, i1, i2, i3)
|
||||
// i0, i1, i2, i3 must not be 0
|
||||
#define LOAD_MSG_AVX2_Y15(i0, i1, i2, i3) \
|
||||
VMOVQ_SI_X15(i0*8); \
|
||||
VMOVQ_SI_X11(i2*8); \
|
||||
VPINSRQ_1_SI_X15(i1*8); \
|
||||
VPINSRQ_1_SI_X11(i3*8); \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
#define LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15() \
|
||||
VMOVQ_SI_X12_0; \
|
||||
VMOVQ_SI_X11(4*8); \
|
||||
VPINSRQ_1_SI_X12(2*8); \
|
||||
VPINSRQ_1_SI_X11(6*8); \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
LOAD_MSG_AVX2_Y13(1, 3, 5, 7); \
|
||||
LOAD_MSG_AVX2_Y14(8, 10, 12, 14); \
|
||||
LOAD_MSG_AVX2_Y15(9, 11, 13, 15)
|
||||
|
||||
#define LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3() \
|
||||
LOAD_MSG_AVX2_Y12(14, 4, 9, 13); \
|
||||
LOAD_MSG_AVX2_Y13(10, 8, 15, 6); \
|
||||
VMOVQ_SI_X11(11*8); \
|
||||
VPSHUFD $0x4E, 0*8(SI), X14; \
|
||||
VPINSRQ_1_SI_X11(5*8); \
|
||||
VINSERTI128 $1, X11, Y14, Y14; \
|
||||
MOVQ i12*8(src), X15; \
|
||||
PINSRQ $1, i13*8(src), X15; \
|
||||
MOVQ i14*8(src), X11; \
|
||||
PINSRQ $1, i15*8(src), X11; \
|
||||
LOAD_MSG_AVX2_Y15(12, 2, 7, 3)
|
||||
|
||||
#define LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4() \
|
||||
VMOVQ_SI_X11(5*8); \
|
||||
VMOVDQU 11*8(SI), X12; \
|
||||
VPINSRQ_1_SI_X11(15*8); \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
VMOVQ_SI_X13(8*8); \
|
||||
VMOVQ_SI_X11(2*8); \
|
||||
VPINSRQ_1_SI_X13_0; \
|
||||
VPINSRQ_1_SI_X11(13*8); \
|
||||
VINSERTI128 $1, X11, Y13, Y13; \
|
||||
LOAD_MSG_AVX2_Y14(10, 3, 7, 9); \
|
||||
LOAD_MSG_AVX2_Y15(14, 6, 1, 4)
|
||||
|
||||
#define LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8() \
|
||||
LOAD_MSG_AVX2_Y12(7, 3, 13, 11); \
|
||||
LOAD_MSG_AVX2_Y13(9, 1, 12, 14); \
|
||||
LOAD_MSG_AVX2_Y14(2, 5, 4, 15); \
|
||||
VMOVQ_SI_X15(6*8); \
|
||||
VMOVQ_SI_X11_0; \
|
||||
VPINSRQ_1_SI_X15(10*8); \
|
||||
VPINSRQ_1_SI_X11(8*8); \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
#define LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13() \
|
||||
LOAD_MSG_AVX2_Y12(9, 5, 2, 10); \
|
||||
VMOVQ_SI_X13_0; \
|
||||
VMOVQ_SI_X11(4*8); \
|
||||
VPINSRQ_1_SI_X13(7*8); \
|
||||
VPINSRQ_1_SI_X11(15*8); \
|
||||
VINSERTI128 $1, X11, Y13, Y13; \
|
||||
LOAD_MSG_AVX2_Y14(14, 11, 6, 3); \
|
||||
LOAD_MSG_AVX2_Y15(1, 12, 8, 13)
|
||||
|
||||
#define LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9() \
|
||||
VMOVQ_SI_X12(2*8); \
|
||||
VMOVQ_SI_X11_0; \
|
||||
VPINSRQ_1_SI_X12(6*8); \
|
||||
VPINSRQ_1_SI_X11(8*8); \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
LOAD_MSG_AVX2_Y13(12, 10, 11, 3); \
|
||||
LOAD_MSG_AVX2_Y14(4, 7, 15, 1); \
|
||||
LOAD_MSG_AVX2_Y15(13, 5, 14, 9)
|
||||
|
||||
#define LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11() \
|
||||
LOAD_MSG_AVX2_Y12(12, 1, 14, 4); \
|
||||
LOAD_MSG_AVX2_Y13(5, 15, 13, 10); \
|
||||
VMOVQ_SI_X14_0; \
|
||||
VPSHUFD $0x4E, 8*8(SI), X11; \
|
||||
VPINSRQ_1_SI_X14(6*8); \
|
||||
VINSERTI128 $1, X11, Y14, Y14; \
|
||||
LOAD_MSG_AVX2_Y15(7, 3, 2, 11)
|
||||
|
||||
#define LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10() \
|
||||
LOAD_MSG_AVX2_Y12(13, 7, 12, 3); \
|
||||
LOAD_MSG_AVX2_Y13(11, 14, 1, 9); \
|
||||
LOAD_MSG_AVX2_Y14(5, 15, 8, 2); \
|
||||
VMOVQ_SI_X15_0; \
|
||||
VMOVQ_SI_X11(6*8); \
|
||||
VPINSRQ_1_SI_X15(4*8); \
|
||||
VPINSRQ_1_SI_X11(10*8); \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
#define LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5() \
|
||||
VMOVQ_SI_X12(6*8); \
|
||||
VMOVQ_SI_X11(11*8); \
|
||||
VPINSRQ_1_SI_X12(14*8); \
|
||||
VPINSRQ_1_SI_X11_0; \
|
||||
VINSERTI128 $1, X11, Y12, Y12; \
|
||||
LOAD_MSG_AVX2_Y13(15, 9, 3, 8); \
|
||||
VMOVQ_SI_X11(1*8); \
|
||||
VMOVDQU 12*8(SI), X14; \
|
||||
VPINSRQ_1_SI_X11(10*8); \
|
||||
VINSERTI128 $1, X11, Y14, Y14; \
|
||||
VMOVQ_SI_X15(2*8); \
|
||||
VMOVDQU 4*8(SI), X11; \
|
||||
VPINSRQ_1_SI_X15(7*8); \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
#define LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0() \
|
||||
LOAD_MSG_AVX2_Y12(10, 8, 7, 1); \
|
||||
VMOVQ_SI_X13(2*8); \
|
||||
VPSHUFD $0x4E, 5*8(SI), X11; \
|
||||
VPINSRQ_1_SI_X13(4*8); \
|
||||
VINSERTI128 $1, X11, Y13, Y13; \
|
||||
LOAD_MSG_AVX2_Y14(15, 9, 3, 13); \
|
||||
VMOVQ_SI_X15(11*8); \
|
||||
VMOVQ_SI_X11(12*8); \
|
||||
VPINSRQ_1_SI_X15(14*8); \
|
||||
VPINSRQ_1_SI_X11_0; \
|
||||
VINSERTI128 $1, X11, Y15, Y15
|
||||
|
||||
// func hashBlocksAVX2(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
@@ -162,34 +317,34 @@ noinc:
|
||||
VMOVDQA Y6, Y2
|
||||
VPXOR 0(SP), Y7, Y3
|
||||
|
||||
LOAD_MSG_AVX2(SI, 0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15)
|
||||
LOAD_MSG_AVX2_0_2_4_6_1_3_5_7_8_10_12_14_9_11_13_15()
|
||||
VMOVDQA Y12, 32(SP)
|
||||
VMOVDQA Y13, 64(SP)
|
||||
VMOVDQA Y14, 96(SP)
|
||||
VMOVDQA Y15, 128(SP)
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3)
|
||||
LOAD_MSG_AVX2_14_4_9_13_10_8_15_6_1_0_11_5_12_2_7_3()
|
||||
VMOVDQA Y12, 160(SP)
|
||||
VMOVDQA Y13, 192(SP)
|
||||
VMOVDQA Y14, 224(SP)
|
||||
VMOVDQA Y15, 256(SP)
|
||||
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4)
|
||||
LOAD_MSG_AVX2_11_12_5_15_8_0_2_13_10_3_7_9_14_6_1_4()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8)
|
||||
LOAD_MSG_AVX2_7_3_13_11_9_1_12_14_2_5_4_15_6_10_0_8()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13)
|
||||
LOAD_MSG_AVX2_9_5_2_10_0_7_4_15_14_11_6_3_1_12_8_13()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9)
|
||||
LOAD_MSG_AVX2_2_6_0_8_12_10_11_3_4_7_15_1_13_5_14_9()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11)
|
||||
LOAD_MSG_AVX2_12_1_14_4_5_15_13_10_0_6_9_8_7_3_2_11()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10)
|
||||
LOAD_MSG_AVX2_13_7_12_3_11_14_1_9_5_15_8_2_0_4_6_10()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5)
|
||||
LOAD_MSG_AVX2_6_14_11_0_15_9_3_8_12_13_1_10_2_7_4_5()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
LOAD_MSG_AVX2(SI, 10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0)
|
||||
LOAD_MSG_AVX2_10_8_7_1_2_4_6_5_15_9_3_13_11_14_12_0()
|
||||
ROUND_AVX2(Y12, Y13, Y14, Y15, Y10, Y4, Y5)
|
||||
|
||||
ROUND_AVX2(32(SP), 64(SP), 96(SP), 128(SP), Y10, Y4, Y5)
|
||||
@@ -209,56 +364,55 @@ noinc:
|
||||
|
||||
VMOVDQU Y8, 0(AX)
|
||||
VMOVDQU Y9, 32(AX)
|
||||
VZEROUPPER
|
||||
|
||||
MOVQ DX, SP
|
||||
RET
|
||||
|
||||
// unfortunately the BYTE representation of VPUNPCKLQDQ and VPUNPCKHQDQ must be used
|
||||
#define VPUNPCKLQDQ_X8_X8_X10 BYTE $0xC4; BYTE $0x41; BYTE $0x39; BYTE $0x6C; BYTE $0xD0
|
||||
#define VPUNPCKHQDQ_X7_X10_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF2
|
||||
#define VPUNPCKLQDQ_X7_X7_X10 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xD7
|
||||
#define VPUNPCKHQDQ_X8_X10_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x39; BYTE $0x6D; BYTE $0xFA
|
||||
#define VPUNPCKLQDQ_X3_X3_X10 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xD3
|
||||
#define VPUNPCKHQDQ_X2_X10_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD2
|
||||
#define VPUNPCKLQDQ_X9_X9_X10 BYTE $0xC4; BYTE $0x41; BYTE $0x31; BYTE $0x6C; BYTE $0xD1
|
||||
#define VPUNPCKHQDQ_X3_X10_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDA
|
||||
#define VPUNPCKLQDQ_X2_X2_X10 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xD2
|
||||
#define VPUNPCKHQDQ_X3_X10_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD2
|
||||
#define VPUNPCKHQDQ_X8_X10_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x39; BYTE $0x6D; BYTE $0xDA
|
||||
#define VPUNPCKHQDQ_X6_X10_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF2
|
||||
#define VPUNPCKHQDQ_X7_X10_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFA
|
||||
#define VPUNPCKLQDQ_X2_X2_X15 BYTE $0xC5; BYTE $0x69; BYTE $0x6C; BYTE $0xFA
|
||||
#define VPUNPCKLQDQ_X3_X3_X15 BYTE $0xC5; BYTE $0x61; BYTE $0x6C; BYTE $0xFB
|
||||
#define VPUNPCKLQDQ_X7_X7_X15 BYTE $0xC5; BYTE $0x41; BYTE $0x6C; BYTE $0xFF
|
||||
#define VPUNPCKLQDQ_X13_X13_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x11; BYTE $0x6C; BYTE $0xFD
|
||||
#define VPUNPCKLQDQ_X14_X14_X15 BYTE $0xC4; BYTE $0x41; BYTE $0x09; BYTE $0x6C; BYTE $0xFE
|
||||
|
||||
#define VPUNPCKHQDQ_X15_X2_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x69; BYTE $0x6D; BYTE $0xD7
|
||||
#define VPUNPCKHQDQ_X15_X3_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xDF
|
||||
#define VPUNPCKHQDQ_X15_X6_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x49; BYTE $0x6D; BYTE $0xF7
|
||||
#define VPUNPCKHQDQ_X15_X7_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xFF
|
||||
#define VPUNPCKHQDQ_X15_X3_X2 BYTE $0xC4; BYTE $0xC1; BYTE $0x61; BYTE $0x6D; BYTE $0xD7
|
||||
#define VPUNPCKHQDQ_X15_X7_X6 BYTE $0xC4; BYTE $0xC1; BYTE $0x41; BYTE $0x6D; BYTE $0xF7
|
||||
#define VPUNPCKHQDQ_X15_X13_X3 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xDF
|
||||
#define VPUNPCKHQDQ_X15_X13_X7 BYTE $0xC4; BYTE $0xC1; BYTE $0x11; BYTE $0x6D; BYTE $0xFF
|
||||
|
||||
// shuffle X2 and X6 using the temp registers X8, X9, X10
|
||||
#define SHUFFLE_AVX() \
|
||||
VMOVDQA X4, X9; \
|
||||
VMOVDQA X5, X4; \
|
||||
VMOVDQA X9, X5; \
|
||||
VMOVDQA X6, X8; \
|
||||
VPUNPCKLQDQ_X8_X8_X10; \
|
||||
VPUNPCKHQDQ_X7_X10_X6; \
|
||||
VPUNPCKLQDQ_X7_X7_X10; \
|
||||
VPUNPCKHQDQ_X8_X10_X7; \
|
||||
VPUNPCKLQDQ_X3_X3_X10; \
|
||||
VMOVDQA X2, X9; \
|
||||
VPUNPCKHQDQ_X2_X10_X2; \
|
||||
VPUNPCKLQDQ_X9_X9_X10; \
|
||||
VPUNPCKHQDQ_X3_X10_X3; \
|
||||
VMOVDQA X6, X13; \
|
||||
VMOVDQA X2, X14; \
|
||||
VMOVDQA X4, X6; \
|
||||
VPUNPCKLQDQ_X13_X13_X15; \
|
||||
VMOVDQA X5, X4; \
|
||||
VMOVDQA X6, X5; \
|
||||
VPUNPCKHQDQ_X15_X7_X6; \
|
||||
VPUNPCKLQDQ_X7_X7_X15; \
|
||||
VPUNPCKHQDQ_X15_X13_X7; \
|
||||
VPUNPCKLQDQ_X3_X3_X15; \
|
||||
VPUNPCKHQDQ_X15_X2_X2; \
|
||||
VPUNPCKLQDQ_X14_X14_X15; \
|
||||
VPUNPCKHQDQ_X15_X3_X3; \
|
||||
|
||||
// inverse shuffle X2 and X6 using the temp registers X8, X9, X10
|
||||
#define SHUFFLE_AVX_INV() \
|
||||
VMOVDQA X4, X9; \
|
||||
VMOVDQA X5, X4; \
|
||||
VMOVDQA X9, X5; \
|
||||
VMOVDQA X2, X8; \
|
||||
VPUNPCKLQDQ_X2_X2_X10; \
|
||||
VPUNPCKHQDQ_X3_X10_X2; \
|
||||
VPUNPCKLQDQ_X3_X3_X10; \
|
||||
VPUNPCKHQDQ_X8_X10_X3; \
|
||||
VPUNPCKLQDQ_X7_X7_X10; \
|
||||
VMOVDQA X6, X9; \
|
||||
VPUNPCKHQDQ_X6_X10_X6; \
|
||||
VPUNPCKLQDQ_X9_X9_X10; \
|
||||
VPUNPCKHQDQ_X7_X10_X7; \
|
||||
VMOVDQA X2, X13; \
|
||||
VMOVDQA X4, X14; \
|
||||
VPUNPCKLQDQ_X2_X2_X15; \
|
||||
VMOVDQA X5, X4; \
|
||||
VPUNPCKHQDQ_X15_X3_X2; \
|
||||
VMOVDQA X14, X5; \
|
||||
VPUNPCKLQDQ_X3_X3_X15; \
|
||||
VMOVDQA X6, X14; \
|
||||
VPUNPCKHQDQ_X15_X13_X3; \
|
||||
VPUNPCKLQDQ_X7_X7_X15; \
|
||||
VPUNPCKHQDQ_X15_X6_X6; \
|
||||
VPUNPCKLQDQ_X14_X14_X15; \
|
||||
VPUNPCKHQDQ_X15_X7_X7; \
|
||||
|
||||
#define HALF_ROUND_AVX(v0, v1, v2, v3, v4, v5, v6, v7, m0, m1, m2, m3, t0, c40, c48) \
|
||||
VPADDQ m0, v0, v0; \
|
||||
@@ -294,28 +448,133 @@ noinc:
|
||||
VPSRLQ $63, v3, v3; \
|
||||
VPXOR t0, v3, v3
|
||||
|
||||
// unfortunately the BYTE representation of VPINSRQ must be used
|
||||
#define VPINSRQ_1_R10_X8_X8 BYTE $0xC4; BYTE $0x43; BYTE $0xB9; BYTE $0x22; BYTE $0xC2; BYTE $0x01
|
||||
#define VPINSRQ_1_R11_X9_X9 BYTE $0xC4; BYTE $0x43; BYTE $0xB1; BYTE $0x22; BYTE $0xCB; BYTE $0x01
|
||||
#define VPINSRQ_1_R12_X10_X10 BYTE $0xC4; BYTE $0x43; BYTE $0xA9; BYTE $0x22; BYTE $0xD4; BYTE $0x01
|
||||
#define VPINSRQ_1_R13_X11_X11 BYTE $0xC4; BYTE $0x43; BYTE $0xA1; BYTE $0x22; BYTE $0xDD; BYTE $0x01
|
||||
// load msg: X12 = (i0, i1), X13 = (i2, i3), X14 = (i4, i5), X15 = (i6, i7)
|
||||
// i0, i1, i2, i3, i4, i5, i6, i7 must not be 0
|
||||
#define LOAD_MSG_AVX(i0, i1, i2, i3, i4, i5, i6, i7) \
|
||||
VMOVQ_SI_X12(i0*8); \
|
||||
VMOVQ_SI_X13(i2*8); \
|
||||
VMOVQ_SI_X14(i4*8); \
|
||||
VMOVQ_SI_X15(i6*8); \
|
||||
VPINSRQ_1_SI_X12(i1*8); \
|
||||
VPINSRQ_1_SI_X13(i3*8); \
|
||||
VPINSRQ_1_SI_X14(i5*8); \
|
||||
VPINSRQ_1_SI_X15(i7*8)
|
||||
|
||||
#define VPINSRQ_1_R9_X8_X8 BYTE $0xC4; BYTE $0x43; BYTE $0xB9; BYTE $0x22; BYTE $0xC1; BYTE $0x01
|
||||
// load msg: X12 = (0, 2), X13 = (4, 6), X14 = (1, 3), X15 = (5, 7)
|
||||
#define LOAD_MSG_AVX_0_2_4_6_1_3_5_7() \
|
||||
VMOVQ_SI_X12_0; \
|
||||
VMOVQ_SI_X13(4*8); \
|
||||
VMOVQ_SI_X14(1*8); \
|
||||
VMOVQ_SI_X15(5*8); \
|
||||
VPINSRQ_1_SI_X12(2*8); \
|
||||
VPINSRQ_1_SI_X13(6*8); \
|
||||
VPINSRQ_1_SI_X14(3*8); \
|
||||
VPINSRQ_1_SI_X15(7*8)
|
||||
|
||||
// load src into X8, X9, X10 and X11 using R10, R11, R12 and R13 for temp registers
|
||||
#define LOAD_MSG_AVX(src, i0, i1, i2, i3, i4, i5, i6, i7) \
|
||||
MOVQ i0*8(src), X8; \
|
||||
MOVQ i1*8(src), R10; \
|
||||
MOVQ i2*8(src), X9; \
|
||||
MOVQ i3*8(src), R11; \
|
||||
MOVQ i4*8(src), X10; \
|
||||
MOVQ i5*8(src), R12; \
|
||||
MOVQ i6*8(src), X11; \
|
||||
MOVQ i7*8(src), R13; \
|
||||
VPINSRQ_1_R10_X8_X8; \
|
||||
VPINSRQ_1_R11_X9_X9; \
|
||||
VPINSRQ_1_R12_X10_X10; \
|
||||
VPINSRQ_1_R13_X11_X11
|
||||
// load msg: X12 = (1, 0), X13 = (11, 5), X14 = (12, 2), X15 = (7, 3)
|
||||
#define LOAD_MSG_AVX_1_0_11_5_12_2_7_3() \
|
||||
VPSHUFD $0x4E, 0*8(SI), X12; \
|
||||
VMOVQ_SI_X13(11*8); \
|
||||
VMOVQ_SI_X14(12*8); \
|
||||
VMOVQ_SI_X15(7*8); \
|
||||
VPINSRQ_1_SI_X13(5*8); \
|
||||
VPINSRQ_1_SI_X14(2*8); \
|
||||
VPINSRQ_1_SI_X15(3*8)
|
||||
|
||||
// load msg: X12 = (11, 12), X13 = (5, 15), X14 = (8, 0), X15 = (2, 13)
|
||||
#define LOAD_MSG_AVX_11_12_5_15_8_0_2_13() \
|
||||
VMOVDQU 11*8(SI), X12; \
|
||||
VMOVQ_SI_X13(5*8); \
|
||||
VMOVQ_SI_X14(8*8); \
|
||||
VMOVQ_SI_X15(2*8); \
|
||||
VPINSRQ_1_SI_X13(15*8); \
|
||||
VPINSRQ_1_SI_X14_0; \
|
||||
VPINSRQ_1_SI_X15(13*8)
|
||||
|
||||
// load msg: X12 = (2, 5), X13 = (4, 15), X14 = (6, 10), X15 = (0, 8)
|
||||
#define LOAD_MSG_AVX_2_5_4_15_6_10_0_8() \
|
||||
VMOVQ_SI_X12(2*8); \
|
||||
VMOVQ_SI_X13(4*8); \
|
||||
VMOVQ_SI_X14(6*8); \
|
||||
VMOVQ_SI_X15_0; \
|
||||
VPINSRQ_1_SI_X12(5*8); \
|
||||
VPINSRQ_1_SI_X13(15*8); \
|
||||
VPINSRQ_1_SI_X14(10*8); \
|
||||
VPINSRQ_1_SI_X15(8*8)
|
||||
|
||||
// load msg: X12 = (9, 5), X13 = (2, 10), X14 = (0, 7), X15 = (4, 15)
|
||||
#define LOAD_MSG_AVX_9_5_2_10_0_7_4_15() \
|
||||
VMOVQ_SI_X12(9*8); \
|
||||
VMOVQ_SI_X13(2*8); \
|
||||
VMOVQ_SI_X14_0; \
|
||||
VMOVQ_SI_X15(4*8); \
|
||||
VPINSRQ_1_SI_X12(5*8); \
|
||||
VPINSRQ_1_SI_X13(10*8); \
|
||||
VPINSRQ_1_SI_X14(7*8); \
|
||||
VPINSRQ_1_SI_X15(15*8)
|
||||
|
||||
// load msg: X12 = (2, 6), X13 = (0, 8), X14 = (12, 10), X15 = (11, 3)
|
||||
#define LOAD_MSG_AVX_2_6_0_8_12_10_11_3() \
|
||||
VMOVQ_SI_X12(2*8); \
|
||||
VMOVQ_SI_X13_0; \
|
||||
VMOVQ_SI_X14(12*8); \
|
||||
VMOVQ_SI_X15(11*8); \
|
||||
VPINSRQ_1_SI_X12(6*8); \
|
||||
VPINSRQ_1_SI_X13(8*8); \
|
||||
VPINSRQ_1_SI_X14(10*8); \
|
||||
VPINSRQ_1_SI_X15(3*8)
|
||||
|
||||
// load msg: X12 = (0, 6), X13 = (9, 8), X14 = (7, 3), X15 = (2, 11)
|
||||
#define LOAD_MSG_AVX_0_6_9_8_7_3_2_11() \
|
||||
MOVQ 0*8(SI), X12; \
|
||||
VPSHUFD $0x4E, 8*8(SI), X13; \
|
||||
MOVQ 7*8(SI), X14; \
|
||||
MOVQ 2*8(SI), X15; \
|
||||
VPINSRQ_1_SI_X12(6*8); \
|
||||
VPINSRQ_1_SI_X14(3*8); \
|
||||
VPINSRQ_1_SI_X15(11*8)
|
||||
|
||||
// load msg: X12 = (6, 14), X13 = (11, 0), X14 = (15, 9), X15 = (3, 8)
|
||||
#define LOAD_MSG_AVX_6_14_11_0_15_9_3_8() \
|
||||
MOVQ 6*8(SI), X12; \
|
||||
MOVQ 11*8(SI), X13; \
|
||||
MOVQ 15*8(SI), X14; \
|
||||
MOVQ 3*8(SI), X15; \
|
||||
VPINSRQ_1_SI_X12(14*8); \
|
||||
VPINSRQ_1_SI_X13_0; \
|
||||
VPINSRQ_1_SI_X14(9*8); \
|
||||
VPINSRQ_1_SI_X15(8*8)
|
||||
|
||||
// load msg: X12 = (5, 15), X13 = (8, 2), X14 = (0, 4), X15 = (6, 10)
|
||||
#define LOAD_MSG_AVX_5_15_8_2_0_4_6_10() \
|
||||
MOVQ 5*8(SI), X12; \
|
||||
MOVQ 8*8(SI), X13; \
|
||||
MOVQ 0*8(SI), X14; \
|
||||
MOVQ 6*8(SI), X15; \
|
||||
VPINSRQ_1_SI_X12(15*8); \
|
||||
VPINSRQ_1_SI_X13(2*8); \
|
||||
VPINSRQ_1_SI_X14(4*8); \
|
||||
VPINSRQ_1_SI_X15(10*8)
|
||||
|
||||
// load msg: X12 = (12, 13), X13 = (1, 10), X14 = (2, 7), X15 = (4, 5)
|
||||
#define LOAD_MSG_AVX_12_13_1_10_2_7_4_5() \
|
||||
VMOVDQU 12*8(SI), X12; \
|
||||
MOVQ 1*8(SI), X13; \
|
||||
MOVQ 2*8(SI), X14; \
|
||||
VPINSRQ_1_SI_X13(10*8); \
|
||||
VPINSRQ_1_SI_X14(7*8); \
|
||||
VMOVDQU 4*8(SI), X15
|
||||
|
||||
// load msg: X12 = (15, 9), X13 = (3, 13), X14 = (11, 14), X15 = (12, 0)
|
||||
#define LOAD_MSG_AVX_15_9_3_13_11_14_12_0() \
|
||||
MOVQ 15*8(SI), X12; \
|
||||
MOVQ 3*8(SI), X13; \
|
||||
MOVQ 11*8(SI), X14; \
|
||||
MOVQ 12*8(SI), X15; \
|
||||
VPINSRQ_1_SI_X12(9*8); \
|
||||
VPINSRQ_1_SI_X13(13*8); \
|
||||
VPINSRQ_1_SI_X14(14*8); \
|
||||
VPINSRQ_1_SI_X15_0
|
||||
|
||||
// func hashBlocksAVX(h *[8]uint64, c *[2]uint64, flag uint64, blocks []byte)
|
||||
TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
|
||||
@@ -331,15 +590,17 @@ TEXT ·hashBlocksAVX(SB), 4, $288-48 // frame size = 272 + 16 byte alignment
|
||||
ANDQ $~15, R9
|
||||
MOVQ R9, SP
|
||||
|
||||
MOVOU ·AVX_c40<>(SB), X13
|
||||
MOVOU ·AVX_c48<>(SB), X14
|
||||
VMOVDQU ·AVX_c40<>(SB), X0
|
||||
VMOVDQU ·AVX_c48<>(SB), X1
|
||||
VMOVDQA X0, X8
|
||||
VMOVDQA X1, X9
|
||||
|
||||
VMOVDQU ·AVX_iv3<>(SB), X0
|
||||
VMOVDQA X0, 0(SP)
|
||||
XORQ CX, 0(SP) // 0(SP) = ·AVX_iv3 ^ (CX || 0)
|
||||
|
||||
VMOVDQU 0(AX), X12
|
||||
VMOVDQU 16(AX), X15
|
||||
VMOVDQU 0(AX), X10
|
||||
VMOVDQU 16(AX), X11
|
||||
VMOVDQU 32(AX), X2
|
||||
VMOVDQU 48(AX), X3
|
||||
|
||||
@@ -353,124 +614,124 @@ loop:
|
||||
INCQ R9
|
||||
|
||||
noinc:
|
||||
MOVQ R8, X8
|
||||
VPINSRQ_1_R9_X8_X8
|
||||
VMOVQ_R8_X15
|
||||
VPINSRQ_1_R9_X15
|
||||
|
||||
VMOVDQA X12, X0
|
||||
VMOVDQA X15, X1
|
||||
VMOVDQA X10, X0
|
||||
VMOVDQA X11, X1
|
||||
VMOVDQU ·AVX_iv0<>(SB), X4
|
||||
VMOVDQU ·AVX_iv1<>(SB), X5
|
||||
VMOVDQU ·AVX_iv2<>(SB), X6
|
||||
|
||||
VPXOR X8, X6, X6
|
||||
VPXOR X15, X6, X6
|
||||
VMOVDQA 0(SP), X7
|
||||
|
||||
LOAD_MSG_AVX(SI, 0, 2, 4, 6, 1, 3, 5, 7)
|
||||
VMOVDQA X8, 16(SP)
|
||||
VMOVDQA X9, 32(SP)
|
||||
VMOVDQA X10, 48(SP)
|
||||
VMOVDQA X11, 64(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_0_2_4_6_1_3_5_7()
|
||||
VMOVDQA X12, 16(SP)
|
||||
VMOVDQA X13, 32(SP)
|
||||
VMOVDQA X14, 48(SP)
|
||||
VMOVDQA X15, 64(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 8, 10, 12, 14, 9, 11, 13, 15)
|
||||
VMOVDQA X8, 80(SP)
|
||||
VMOVDQA X9, 96(SP)
|
||||
VMOVDQA X10, 112(SP)
|
||||
VMOVDQA X11, 128(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(8, 10, 12, 14, 9, 11, 13, 15)
|
||||
VMOVDQA X12, 80(SP)
|
||||
VMOVDQA X13, 96(SP)
|
||||
VMOVDQA X14, 112(SP)
|
||||
VMOVDQA X15, 128(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 14, 4, 9, 13, 10, 8, 15, 6)
|
||||
VMOVDQA X8, 144(SP)
|
||||
VMOVDQA X9, 160(SP)
|
||||
VMOVDQA X10, 176(SP)
|
||||
VMOVDQA X11, 192(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(14, 4, 9, 13, 10, 8, 15, 6)
|
||||
VMOVDQA X12, 144(SP)
|
||||
VMOVDQA X13, 160(SP)
|
||||
VMOVDQA X14, 176(SP)
|
||||
VMOVDQA X15, 192(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 1, 0, 11, 5, 12, 2, 7, 3)
|
||||
VMOVDQA X8, 208(SP)
|
||||
VMOVDQA X9, 224(SP)
|
||||
VMOVDQA X10, 240(SP)
|
||||
VMOVDQA X11, 256(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_1_0_11_5_12_2_7_3()
|
||||
VMOVDQA X12, 208(SP)
|
||||
VMOVDQA X13, 224(SP)
|
||||
VMOVDQA X14, 240(SP)
|
||||
VMOVDQA X15, 256(SP)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 11, 12, 5, 15, 8, 0, 2, 13)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_11_12_5_15_8_0_2_13()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 10, 3, 7, 9, 14, 6, 1, 4)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(10, 3, 7, 9, 14, 6, 1, 4)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 7, 3, 13, 11, 9, 1, 12, 14)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(7, 3, 13, 11, 9, 1, 12, 14)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 2, 5, 4, 15, 6, 10, 0, 8)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_2_5_4_15_6_10_0_8()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 9, 5, 2, 10, 0, 7, 4, 15)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_9_5_2_10_0_7_4_15()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 14, 11, 6, 3, 1, 12, 8, 13)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(14, 11, 6, 3, 1, 12, 8, 13)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 2, 6, 0, 8, 12, 10, 11, 3)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_2_6_0_8_12_10_11_3()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 4, 7, 15, 1, 13, 5, 14, 9)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(4, 7, 15, 1, 13, 5, 14, 9)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 12, 1, 14, 4, 5, 15, 13, 10)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(12, 1, 14, 4, 5, 15, 13, 10)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 0, 6, 9, 8, 7, 3, 2, 11)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_0_6_9_8_7_3_2_11()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 13, 7, 12, 3, 11, 14, 1, 9)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(13, 7, 12, 3, 11, 14, 1, 9)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 5, 15, 8, 2, 0, 4, 6, 10)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_5_15_8_2_0_4_6_10()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 6, 14, 11, 0, 15, 9, 3, 8)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_6_14_11_0_15_9_3_8()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 12, 13, 1, 10, 2, 7, 4, 5)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_12_13_1_10_2_7_4_5()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
LOAD_MSG_AVX(SI, 10, 8, 7, 1, 2, 4, 6, 5)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX(10, 8, 7, 1, 2, 4, 6, 5)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
LOAD_MSG_AVX(SI, 15, 9, 3, 13, 11, 14, 12, 0)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X11, X13, X14)
|
||||
LOAD_MSG_AVX_15_9_3_13_11_14_12_0()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, X12, X13, X14, X15, X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X11, X13, X14)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 16(SP), 32(SP), 48(SP), 64(SP), X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X11, X13, X14)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 80(SP), 96(SP), 112(SP), 128(SP), X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X11, X13, X14)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 144(SP), 160(SP), 176(SP), 192(SP), X15, X8, X9)
|
||||
SHUFFLE_AVX()
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X11, X13, X14)
|
||||
HALF_ROUND_AVX(X0, X1, X2, X3, X4, X5, X6, X7, 208(SP), 224(SP), 240(SP), 256(SP), X15, X8, X9)
|
||||
SHUFFLE_AVX_INV()
|
||||
|
||||
VMOVDQU 32(AX), X10
|
||||
VMOVDQU 48(AX), X11
|
||||
VPXOR X0, X12, X12
|
||||
VPXOR X1, X15, X15
|
||||
VPXOR X2, X10, X10
|
||||
VPXOR X3, X11, X11
|
||||
VPXOR X4, X12, X12
|
||||
VPXOR X5, X15, X15
|
||||
VPXOR X6, X10, X2
|
||||
VPXOR X7, X11, X3
|
||||
VMOVDQU 32(AX), X14
|
||||
VMOVDQU 48(AX), X15
|
||||
VPXOR X0, X10, X10
|
||||
VPXOR X1, X11, X11
|
||||
VPXOR X2, X14, X14
|
||||
VPXOR X3, X15, X15
|
||||
VPXOR X4, X10, X10
|
||||
VPXOR X5, X11, X11
|
||||
VPXOR X6, X14, X2
|
||||
VPXOR X7, X15, X3
|
||||
VMOVDQU X2, 32(AX)
|
||||
VMOVDQU X3, 48(AX)
|
||||
|
||||
@@ -478,12 +739,11 @@ noinc:
|
||||
SUBQ $128, DI
|
||||
JNE loop
|
||||
|
||||
VMOVDQU X12, 0(AX)
|
||||
VMOVDQU X15, 16(AX)
|
||||
VMOVDQU X10, 0(AX)
|
||||
VMOVDQU X11, 16(AX)
|
||||
|
||||
MOVQ R8, 0(BX)
|
||||
MOVQ R9, 8(BX)
|
||||
|
||||
VZEROUPPER
|
||||
|
||||
MOVQ BP, SP
|
||||
|
||||
32
vendor/golang.org/x/crypto/blake2b/register.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,32 @@
|
||||
// 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.
|
||||
|
||||
// +build go1.9
|
||||
|
||||
package blake2b
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
)
|
||||
|
||||
func init() {
|
||||
newHash256 := func() hash.Hash {
|
||||
h, _ := New256(nil)
|
||||
return h
|
||||
}
|
||||
newHash384 := func() hash.Hash {
|
||||
h, _ := New384(nil)
|
||||
return h
|
||||
}
|
||||
|
||||
newHash512 := func() hash.Hash {
|
||||
h, _ := New512(nil)
|
||||
return h
|
||||
}
|
||||
|
||||
crypto.RegisterHash(crypto.BLAKE2b_256, newHash256)
|
||||
crypto.RegisterHash(crypto.BLAKE2b_384, newHash384)
|
||||
crypto.RegisterHash(crypto.BLAKE2b_512, newHash512)
|
||||
}
|
||||
21
vendor/golang.org/x/crypto/blake2s/register.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
// +build go1.9
|
||||
|
||||
package blake2s
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"hash"
|
||||
)
|
||||
|
||||
func init() {
|
||||
newHash256 := func() hash.Hash {
|
||||
h, _ := New256(nil)
|
||||
return h
|
||||
}
|
||||
|
||||
crypto.RegisterHash(crypto.BLAKE2s_256, newHash256)
|
||||
}
|
||||
604
vendor/golang.org/x/crypto/cryptobyte/asn1.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,604 @@
|
||||
// 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 cryptobyte
|
||||
|
||||
import (
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This file contains ASN.1-related methods for String and Builder.
|
||||
|
||||
// Tag represents an ASN.1 tag number and class (together also referred to as
|
||||
// identifier octets). Methods in this package only support the low-tag-number
|
||||
// form, i.e. a single identifier octet with bits 7-8 encoding the class and
|
||||
// bits 1-6 encoding the tag number.
|
||||
type Tag uint8
|
||||
|
||||
// Contructed returns t with the context-specific class bit set.
|
||||
func (t Tag) ContextSpecific() Tag { return t | 0x80 }
|
||||
|
||||
// Contructed returns t with the constructed class bit set.
|
||||
func (t Tag) Constructed() Tag { return t | 0x20 }
|
||||
|
||||
// Builder
|
||||
|
||||
// AddASN1Int64 appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1Int64(v int64) {
|
||||
b.addASN1Signed(asn1.TagInteger, v)
|
||||
}
|
||||
|
||||
// AddASN1Enum appends a DER-encoded ASN.1 ENUMERATION.
|
||||
func (b *Builder) AddASN1Enum(v int64) {
|
||||
b.addASN1Signed(asn1.TagEnum, v)
|
||||
}
|
||||
|
||||
func (b *Builder) addASN1Signed(tag Tag, v int64) {
|
||||
b.AddASN1(tag, func(c *Builder) {
|
||||
length := 1
|
||||
for i := v; i >= 0x80 || i < -0x80; i >>= 8 {
|
||||
length++
|
||||
}
|
||||
|
||||
for ; length > 0; length-- {
|
||||
i := v >> uint((length-1)*8) & 0xff
|
||||
c.AddUint8(uint8(i))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1Uint64 appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1Uint64(v uint64) {
|
||||
b.AddASN1(asn1.TagInteger, func(c *Builder) {
|
||||
length := 1
|
||||
for i := v; i >= 0x80; i >>= 8 {
|
||||
length++
|
||||
}
|
||||
|
||||
for ; length > 0; length-- {
|
||||
i := v >> uint((length-1)*8) & 0xff
|
||||
c.AddUint8(uint8(i))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1BigInt appends a DER-encoded ASN.1 INTEGER.
|
||||
func (b *Builder) AddASN1BigInt(n *big.Int) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b.AddASN1(asn1.TagInteger, func(c *Builder) {
|
||||
if n.Sign() < 0 {
|
||||
// A negative number has to be converted to two's-complement form. So we
|
||||
// invert and subtract 1. If the most-significant-bit isn't set then
|
||||
// we'll need to pad the beginning with 0xff in order to keep the number
|
||||
// negative.
|
||||
nMinus1 := new(big.Int).Neg(n)
|
||||
nMinus1.Sub(nMinus1, bigOne)
|
||||
bytes := nMinus1.Bytes()
|
||||
for i := range bytes {
|
||||
bytes[i] ^= 0xff
|
||||
}
|
||||
if bytes[0]&0x80 == 0 {
|
||||
c.add(0xff)
|
||||
}
|
||||
c.add(bytes...)
|
||||
} else if n.Sign() == 0 {
|
||||
c.add(0)
|
||||
} else {
|
||||
bytes := n.Bytes()
|
||||
if bytes[0]&0x80 != 0 {
|
||||
c.add(0)
|
||||
}
|
||||
c.add(bytes...)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1OctetString appends a DER-encoded ASN.1 OCTET STRING.
|
||||
func (b *Builder) AddASN1OctetString(bytes []byte) {
|
||||
b.AddASN1(asn1.TagOctetString, func(c *Builder) {
|
||||
c.AddBytes(bytes)
|
||||
})
|
||||
}
|
||||
|
||||
const generalizedTimeFormatStr = "20060102150405Z0700"
|
||||
|
||||
// AddASN1GeneralizedTime appends a DER-encoded ASN.1 GENERALIZEDTIME.
|
||||
func (b *Builder) AddASN1GeneralizedTime(t time.Time) {
|
||||
if t.Year() < 0 || t.Year() > 9999 {
|
||||
b.err = fmt.Errorf("cryptobyte: cannot represent %v as a GeneralizedTime", t)
|
||||
return
|
||||
}
|
||||
b.AddASN1(asn1.TagGeneralizedTime, func(c *Builder) {
|
||||
c.AddBytes([]byte(t.Format(generalizedTimeFormatStr)))
|
||||
})
|
||||
}
|
||||
|
||||
// AddASN1BitString appends a DER-encoded ASN.1 BIT STRING.
|
||||
func (b *Builder) AddASN1BitString(s asn1.BitString) {
|
||||
// TODO(martinkr): Implement.
|
||||
b.MarshalASN1(s)
|
||||
}
|
||||
|
||||
// MarshalASN1 calls asn1.Marshal on its input and appends the result if
|
||||
// successful or records an error if one occurred.
|
||||
func (b *Builder) MarshalASN1(v interface{}) {
|
||||
// NOTE(martinkr): This is somewhat of a hack to allow propagation of
|
||||
// asn1.Marshal errors into Builder.err. N.B. if you call MarshalASN1 with a
|
||||
// value embedded into a struct, its tag information is lost.
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
bytes, err := asn1.Marshal(v)
|
||||
if err != nil {
|
||||
b.err = err
|
||||
return
|
||||
}
|
||||
b.AddBytes(bytes)
|
||||
}
|
||||
|
||||
// AddASN1 appends an ASN.1 object. The object is prefixed with the given tag.
|
||||
// Tags greater than 30 are not supported and result in an error (i.e.
|
||||
// low-tag-number form only). The child builder passed to the
|
||||
// BuilderContinuation can be used to build the content of the ASN.1 object.
|
||||
func (b *Builder) AddASN1(tag Tag, f BuilderContinuation) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
// Identifiers with the low five bits set indicate high-tag-number format
|
||||
// (two or more octets), which we don't support.
|
||||
if tag&0x1f == 0x1f {
|
||||
b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag)
|
||||
return
|
||||
}
|
||||
b.AddUint8(uint8(tag))
|
||||
b.addLengthPrefixed(1, true, f)
|
||||
}
|
||||
|
||||
// String
|
||||
|
||||
var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
|
||||
|
||||
// ReadASN1Integer decodes an ASN.1 INTEGER into out and advances. If out does
|
||||
// not point to an integer or to a big.Int, it panics. It returns true on
|
||||
// success and false on error.
|
||||
func (s *String) ReadASN1Integer(out interface{}) bool {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
panic("out is not a pointer")
|
||||
}
|
||||
switch reflect.ValueOf(out).Elem().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
var i int64
|
||||
if !s.readASN1Int64(&i) || reflect.ValueOf(out).Elem().OverflowInt(i) {
|
||||
return false
|
||||
}
|
||||
reflect.ValueOf(out).Elem().SetInt(i)
|
||||
return true
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
var u uint64
|
||||
if !s.readASN1Uint64(&u) || reflect.ValueOf(out).Elem().OverflowUint(u) {
|
||||
return false
|
||||
}
|
||||
reflect.ValueOf(out).Elem().SetUint(u)
|
||||
return true
|
||||
case reflect.Struct:
|
||||
if reflect.TypeOf(out).Elem() == bigIntType {
|
||||
return s.readASN1BigInt(out.(*big.Int))
|
||||
}
|
||||
}
|
||||
panic("out does not point to an integer type")
|
||||
}
|
||||
|
||||
func checkASN1Integer(bytes []byte) bool {
|
||||
if len(bytes) == 0 {
|
||||
// An INTEGER is encoded with at least one octet.
|
||||
return false
|
||||
}
|
||||
if len(bytes) == 1 {
|
||||
return true
|
||||
}
|
||||
if bytes[0] == 0 && bytes[1]&0x80 == 0 || bytes[0] == 0xff && bytes[1]&0x80 == 0x80 {
|
||||
// Value is not minimally encoded.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var bigOne = big.NewInt(1)
|
||||
|
||||
func (s *String) readASN1BigInt(out *big.Int) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) {
|
||||
return false
|
||||
}
|
||||
if bytes[0]&0x80 == 0x80 {
|
||||
// Negative number.
|
||||
neg := make([]byte, len(bytes))
|
||||
for i, b := range bytes {
|
||||
neg[i] = ^b
|
||||
}
|
||||
out.SetBytes(neg)
|
||||
out.Add(out, bigOne)
|
||||
out.Neg(out)
|
||||
} else {
|
||||
out.SetBytes(bytes)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readASN1Int64(out *int64) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) || !asn1Signed(out, bytes) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func asn1Signed(out *int64, n []byte) bool {
|
||||
length := len(n)
|
||||
if length > 8 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
*out <<= 8
|
||||
*out |= int64(n[i])
|
||||
}
|
||||
// Shift up and down in order to sign extend the result.
|
||||
*out <<= 64 - uint8(length)*8
|
||||
*out >>= 64 - uint8(length)*8
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readASN1Uint64(out *uint64) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagInteger) || !checkASN1Integer(bytes) || !asn1Unsigned(out, bytes) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func asn1Unsigned(out *uint64, n []byte) bool {
|
||||
length := len(n)
|
||||
if length > 9 || length == 9 && n[0] != 0 {
|
||||
// Too large for uint64.
|
||||
return false
|
||||
}
|
||||
if n[0]&0x80 != 0 {
|
||||
// Negative number.
|
||||
return false
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
*out <<= 8
|
||||
*out |= uint64(n[i])
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Enum decodes an ASN.1 ENUMERATION into out and advances. It returns
|
||||
// true on success and false on error.
|
||||
func (s *String) ReadASN1Enum(out *int) bool {
|
||||
var bytes String
|
||||
var i int64
|
||||
if !s.ReadASN1(&bytes, asn1.TagEnum) || !checkASN1Integer(bytes) || !asn1Signed(&i, bytes) {
|
||||
return false
|
||||
}
|
||||
if int64(int(i)) != i {
|
||||
return false
|
||||
}
|
||||
*out = int(i)
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readBase128Int(out *int) bool {
|
||||
ret := 0
|
||||
for i := 0; len(*s) > 0; i++ {
|
||||
if i == 4 {
|
||||
return false
|
||||
}
|
||||
ret <<= 7
|
||||
b := s.read(1)[0]
|
||||
ret |= int(b & 0x7f)
|
||||
if b&0x80 == 0 {
|
||||
*out = ret
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false // truncated
|
||||
}
|
||||
|
||||
// ReadASN1ObjectIdentifier decodes an ASN.1 OBJECT IDENTIFIER into out and
|
||||
// advances. It returns true on success and false on error.
|
||||
func (s *String) ReadASN1ObjectIdentifier(out *asn1.ObjectIdentifier) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagOID) || len(bytes) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// In the worst case, we get two elements from the first byte (which is
|
||||
// encoded differently) and then every varint is a single byte long.
|
||||
components := make([]int, len(bytes)+1)
|
||||
|
||||
// The first varint is 40*value1 + value2:
|
||||
// According to this packing, value1 can take the values 0, 1 and 2 only.
|
||||
// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
|
||||
// then there are no restrictions on value2.
|
||||
var v int
|
||||
if !bytes.readBase128Int(&v) {
|
||||
return false
|
||||
}
|
||||
if v < 80 {
|
||||
components[0] = v / 40
|
||||
components[1] = v % 40
|
||||
} else {
|
||||
components[0] = 2
|
||||
components[1] = v - 80
|
||||
}
|
||||
|
||||
i := 2
|
||||
for ; len(bytes) > 0; i++ {
|
||||
if !bytes.readBase128Int(&v) {
|
||||
return false
|
||||
}
|
||||
components[i] = v
|
||||
}
|
||||
*out = components[:i]
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1GeneralizedTime decodes an ASN.1 GENERALIZEDTIME into out and
|
||||
// advances. It returns true on success and false on error.
|
||||
func (s *String) ReadASN1GeneralizedTime(out *time.Time) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagGeneralizedTime) {
|
||||
return false
|
||||
}
|
||||
t := string(bytes)
|
||||
res, err := time.Parse(generalizedTimeFormatStr, t)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if serialized := res.Format(generalizedTimeFormatStr); serialized != t {
|
||||
return false
|
||||
}
|
||||
*out = res
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1BitString decodes an ASN.1 BIT STRING into out and advances. It
|
||||
// returns true on success and false on error.
|
||||
func (s *String) ReadASN1BitString(out *asn1.BitString) bool {
|
||||
var bytes String
|
||||
if !s.ReadASN1(&bytes, asn1.TagBitString) || len(bytes) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
paddingBits := uint8(bytes[0])
|
||||
bytes = bytes[1:]
|
||||
if paddingBits > 7 ||
|
||||
len(bytes) == 0 && paddingBits != 0 ||
|
||||
len(bytes) > 0 && bytes[len(bytes)-1]&(1<<paddingBits-1) != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
out.BitLength = len(bytes)*8 - int(paddingBits)
|
||||
out.Bytes = bytes
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Bytes reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
func (s *String) ReadASN1Bytes(out *[]byte, tag Tag) bool {
|
||||
return s.ReadASN1((*String)(out), tag)
|
||||
}
|
||||
|
||||
// ReadASN1 reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadASN1(out *String, tag Tag) bool {
|
||||
var t Tag
|
||||
if !s.ReadAnyASN1(out, &t) || t != tag {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadASN1Element reads the contents of a DER-encoded ASN.1 element (including
|
||||
// tag and length bytes) into out, and advances. The element must match the
|
||||
// given tag. It returns true on success and false on error.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadASN1Element(out *String, tag Tag) bool {
|
||||
var t Tag
|
||||
if !s.ReadAnyASN1Element(out, &t) || t != tag {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadAnyASN1 reads the contents of a DER-encoded ASN.1 element (not including
|
||||
// tag and length bytes) into out, sets outTag to its tag, and advances. It
|
||||
// returns true on success and false on error.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadAnyASN1(out *String, outTag *Tag) bool {
|
||||
return s.readASN1(out, outTag, true /* skip header */)
|
||||
}
|
||||
|
||||
// ReadAnyASN1Element reads the contents of a DER-encoded ASN.1 element
|
||||
// (including tag and length bytes) into out, sets outTag to is tag, and
|
||||
// advances. It returns true on success and false on error.
|
||||
//
|
||||
// Tags greater than 30 are not supported (i.e. low-tag-number format only).
|
||||
func (s *String) ReadAnyASN1Element(out *String, outTag *Tag) bool {
|
||||
return s.readASN1(out, outTag, false /* include header */)
|
||||
}
|
||||
|
||||
// PeekASN1Tag returns true if the next ASN.1 value on the string starts with
|
||||
// the given tag.
|
||||
func (s String) PeekASN1Tag(tag Tag) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
return Tag(s[0]) == tag
|
||||
}
|
||||
|
||||
// ReadOptionalASN1 attempts to read the contents of a DER-encoded ASN.Element
|
||||
// (not including tag and length bytes) tagged with the given tag into out. It
|
||||
// stores whether an element with the tag was found in outPresent, unless
|
||||
// outPresent is nil. It returns true on success and false on error.
|
||||
func (s *String) ReadOptionalASN1(out *String, outPresent *bool, tag Tag) bool {
|
||||
present := s.PeekASN1Tag(tag)
|
||||
if outPresent != nil {
|
||||
*outPresent = present
|
||||
}
|
||||
if present && !s.ReadASN1(out, tag) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadOptionalASN1Integer attempts to read an optional ASN.1 INTEGER
|
||||
// explicitly tagged with tag into out and advances. If no element with a
|
||||
// matching tag is present, it writes defaultValue into out instead. If out
|
||||
// does not point to an integer or to a big.Int, it panics. It returns true on
|
||||
// success and false on error.
|
||||
func (s *String) ReadOptionalASN1Integer(out interface{}, tag Tag, defaultValue interface{}) bool {
|
||||
if reflect.TypeOf(out).Kind() != reflect.Ptr {
|
||||
panic("out is not a pointer")
|
||||
}
|
||||
var present bool
|
||||
var i String
|
||||
if !s.ReadOptionalASN1(&i, &present, tag) {
|
||||
return false
|
||||
}
|
||||
if !present {
|
||||
switch reflect.ValueOf(out).Elem().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
|
||||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
reflect.ValueOf(out).Elem().Set(reflect.ValueOf(defaultValue))
|
||||
case reflect.Struct:
|
||||
if reflect.TypeOf(out).Elem() != bigIntType {
|
||||
panic("invalid integer type")
|
||||
}
|
||||
if reflect.TypeOf(defaultValue).Kind() != reflect.Ptr ||
|
||||
reflect.TypeOf(defaultValue).Elem() != bigIntType {
|
||||
panic("out points to big.Int, but defaultValue does not")
|
||||
}
|
||||
out.(*big.Int).Set(defaultValue.(*big.Int))
|
||||
default:
|
||||
panic("invalid integer type")
|
||||
}
|
||||
return true
|
||||
}
|
||||
if !i.ReadASN1Integer(out) || !i.Empty() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadOptionalASN1OctetString attempts to read an optional ASN.1 OCTET STRING
|
||||
// explicitly tagged with tag into out and advances. If no element with a
|
||||
// matching tag is present, it writes defaultValue into out instead. It returns
|
||||
// true on success and false on error.
|
||||
func (s *String) ReadOptionalASN1OctetString(out *[]byte, outPresent *bool, tag Tag) bool {
|
||||
var present bool
|
||||
var child String
|
||||
if !s.ReadOptionalASN1(&child, &present, tag) {
|
||||
return false
|
||||
}
|
||||
if outPresent != nil {
|
||||
*outPresent = present
|
||||
}
|
||||
if present {
|
||||
var oct String
|
||||
if !child.ReadASN1(&oct, asn1.TagOctetString) || !child.Empty() {
|
||||
return false
|
||||
}
|
||||
*out = oct
|
||||
} else {
|
||||
*out = nil
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readASN1(out *String, outTag *Tag, skipHeader bool) bool {
|
||||
if len(*s) < 2 {
|
||||
return false
|
||||
}
|
||||
tag, lenByte := (*s)[0], (*s)[1]
|
||||
|
||||
if tag&0x1f == 0x1f {
|
||||
// ITU-T X.690 section 8.1.2
|
||||
//
|
||||
// An identifier octet with a tag part of 0x1f indicates a high-tag-number
|
||||
// form identifier with two or more octets. We only support tags less than
|
||||
// 31 (i.e. low-tag-number form, single octet identifier).
|
||||
return false
|
||||
}
|
||||
|
||||
if outTag != nil {
|
||||
*outTag = Tag(tag)
|
||||
}
|
||||
|
||||
// ITU-T X.690 section 8.1.3
|
||||
//
|
||||
// Bit 8 of the first length byte indicates whether the length is short- or
|
||||
// long-form.
|
||||
var length, headerLen uint32 // length includes headerLen
|
||||
if lenByte&0x80 == 0 {
|
||||
// Short-form length (section 8.1.3.4), encoded in bits 1-7.
|
||||
length = uint32(lenByte) + 2
|
||||
headerLen = 2
|
||||
} else {
|
||||
// Long-form length (section 8.1.3.5). Bits 1-7 encode the number of octets
|
||||
// used to encode the length.
|
||||
lenLen := lenByte & 0x7f
|
||||
var len32 uint32
|
||||
|
||||
if lenLen == 0 || lenLen > 4 || len(*s) < int(2+lenLen) {
|
||||
return false
|
||||
}
|
||||
|
||||
lenBytes := String((*s)[2 : 2+lenLen])
|
||||
if !lenBytes.readUnsigned(&len32, int(lenLen)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// ITU-T X.690 section 10.1 (DER length forms) requires encoding the length
|
||||
// with the minimum number of octets.
|
||||
if len32 < 128 {
|
||||
// Length should have used short-form encoding.
|
||||
return false
|
||||
}
|
||||
if len32>>((lenLen-1)*8) == 0 {
|
||||
// Leading octet is 0. Length should have been at least one byte shorter.
|
||||
return false
|
||||
}
|
||||
|
||||
headerLen = 2 + uint32(lenLen)
|
||||
if headerLen+len32 < len32 {
|
||||
// Overflow.
|
||||
return false
|
||||
}
|
||||
length = headerLen + len32
|
||||
}
|
||||
|
||||
if uint32(int(length)) != length || !s.ReadBytes((*[]byte)(out), int(length)) {
|
||||
return false
|
||||
}
|
||||
if skipHeader && !out.Skip(int(headerLen)) {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
285
vendor/golang.org/x/crypto/cryptobyte/asn1_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,285 @@
|
||||
// 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 cryptobyte
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
type readASN1Test struct {
|
||||
name string
|
||||
in []byte
|
||||
tag Tag
|
||||
ok bool
|
||||
out interface{}
|
||||
}
|
||||
|
||||
var readASN1TestData = []readASN1Test{
|
||||
{"valid", []byte{0x30, 2, 1, 2}, 0x30, true, []byte{1, 2}},
|
||||
{"truncated", []byte{0x30, 3, 1, 2}, 0x30, false, nil},
|
||||
{"zero length of length", []byte{0x30, 0x80}, 0x30, false, nil},
|
||||
{"invalid long form length", []byte{0x30, 0x81, 1, 1}, 0x30, false, nil},
|
||||
{"non-minimal length", append([]byte{0x30, 0x82, 0, 0x80}, make([]byte, 0x80)...), 0x30, false, nil},
|
||||
{"invalid tag", []byte{0xa1, 3, 0x4, 1, 1}, 31, false, nil},
|
||||
{"high tag", []byte{0x1f, 0x81, 0x80, 0x01, 2, 1, 2}, 0xff /* actually 0x4001, but tag is uint8 */, false, nil},
|
||||
}
|
||||
|
||||
func TestReadASN1(t *testing.T) {
|
||||
for _, test := range readASN1TestData {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
var in, out String = test.in, nil
|
||||
ok := in.ReadASN1(&out, test.tag)
|
||||
if ok != test.ok || ok && !bytes.Equal(out, test.out.([]byte)) {
|
||||
t.Errorf("in.ReadASN1() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1Optional(t *testing.T) {
|
||||
var empty String
|
||||
var present bool
|
||||
ok := empty.ReadOptionalASN1(nil, &present, 0xa0)
|
||||
if !ok || present {
|
||||
t.Errorf("empty.ReadOptionalASN1() = %v, want true; present = %v want false", ok, present)
|
||||
}
|
||||
|
||||
var in, out String = []byte{0xa1, 3, 0x4, 1, 1}, nil
|
||||
ok = in.ReadOptionalASN1(&out, &present, 0xa0)
|
||||
if !ok || present {
|
||||
t.Errorf("in.ReadOptionalASN1() = %v, want true, present = %v, want false", ok, present)
|
||||
}
|
||||
ok = in.ReadOptionalASN1(&out, &present, 0xa1)
|
||||
wantBytes := []byte{4, 1, 1}
|
||||
if !ok || !present || !bytes.Equal(out, wantBytes) {
|
||||
t.Errorf("in.ReadOptionalASN1() = %v, want true; present = %v, want true; out = %v, want = %v", ok, present, out, wantBytes)
|
||||
}
|
||||
}
|
||||
|
||||
var optionalOctetStringTestData = []struct {
|
||||
readASN1Test
|
||||
present bool
|
||||
}{
|
||||
{readASN1Test{"empty", []byte{}, 0xa0, true, []byte{}}, false},
|
||||
{readASN1Test{"invalid", []byte{0xa1, 3, 0x4, 2, 1}, 0xa1, false, []byte{}}, true},
|
||||
{readASN1Test{"missing", []byte{0xa1, 3, 0x4, 1, 1}, 0xa0, true, []byte{}}, false},
|
||||
{readASN1Test{"present", []byte{0xa1, 3, 0x4, 1, 1}, 0xa1, true, []byte{1}}, true},
|
||||
}
|
||||
|
||||
func TestReadASN1OptionalOctetString(t *testing.T) {
|
||||
for _, test := range optionalOctetStringTestData {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
in := String(test.in)
|
||||
var out []byte
|
||||
var present bool
|
||||
ok := in.ReadOptionalASN1OctetString(&out, &present, test.tag)
|
||||
if ok != test.ok || present != test.present || !bytes.Equal(out, test.out.([]byte)) {
|
||||
t.Errorf("in.ReadOptionalASN1OctetString() = %v, want %v; present = %v want %v; out = %v, want %v", ok, test.ok, present, test.present, out, test.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const defaultInt = -1
|
||||
|
||||
var optionalIntTestData = []readASN1Test{
|
||||
{"empty", []byte{}, 0xa0, true, defaultInt},
|
||||
{"invalid", []byte{0xa1, 3, 0x2, 2, 127}, 0xa1, false, 0},
|
||||
{"missing", []byte{0xa1, 3, 0x2, 1, 127}, 0xa0, true, defaultInt},
|
||||
{"present", []byte{0xa1, 3, 0x2, 1, 42}, 0xa1, true, 42},
|
||||
}
|
||||
|
||||
func TestReadASN1OptionalInteger(t *testing.T) {
|
||||
for _, test := range optionalIntTestData {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
in := String(test.in)
|
||||
var out int
|
||||
ok := in.ReadOptionalASN1Integer(&out, test.tag, defaultInt)
|
||||
if ok != test.ok || ok && out != test.out.(int) {
|
||||
t.Errorf("in.ReadOptionalASN1Integer() = %v, want %v; out = %v, want %v", ok, test.ok, out, test.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1IntegerSigned(t *testing.T) {
|
||||
testData64 := []struct {
|
||||
in []byte
|
||||
out int64
|
||||
}{
|
||||
{[]byte{2, 3, 128, 0, 0}, -0x800000},
|
||||
{[]byte{2, 2, 255, 0}, -256},
|
||||
{[]byte{2, 2, 255, 127}, -129},
|
||||
{[]byte{2, 1, 128}, -128},
|
||||
{[]byte{2, 1, 255}, -1},
|
||||
{[]byte{2, 1, 0}, 0},
|
||||
{[]byte{2, 1, 1}, 1},
|
||||
{[]byte{2, 1, 2}, 2},
|
||||
{[]byte{2, 1, 127}, 127},
|
||||
{[]byte{2, 2, 0, 128}, 128},
|
||||
{[]byte{2, 2, 1, 0}, 256},
|
||||
{[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
|
||||
}
|
||||
for i, test := range testData64 {
|
||||
in := String(test.in)
|
||||
var out int64
|
||||
ok := in.ReadASN1Integer(&out)
|
||||
if !ok || out != test.out {
|
||||
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
|
||||
}
|
||||
}
|
||||
|
||||
// Repeat the same cases, reading into a big.Int.
|
||||
t.Run("big.Int", func(t *testing.T) {
|
||||
for i, test := range testData64 {
|
||||
in := String(test.in)
|
||||
var out big.Int
|
||||
ok := in.ReadASN1Integer(&out)
|
||||
if !ok || out.Int64() != test.out {
|
||||
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out.Int64(), test.out)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestReadASN1IntegerUnsigned(t *testing.T) {
|
||||
testData := []struct {
|
||||
in []byte
|
||||
out uint64
|
||||
}{
|
||||
{[]byte{2, 1, 0}, 0},
|
||||
{[]byte{2, 1, 1}, 1},
|
||||
{[]byte{2, 1, 2}, 2},
|
||||
{[]byte{2, 1, 127}, 127},
|
||||
{[]byte{2, 2, 0, 128}, 128},
|
||||
{[]byte{2, 2, 1, 0}, 256},
|
||||
{[]byte{2, 4, 0, 128, 0, 0}, 0x800000},
|
||||
{[]byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}, 0x7fffffffffffffff},
|
||||
{[]byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}, 0x8000000000000000},
|
||||
{[]byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}, 0xffffffffffffffff},
|
||||
}
|
||||
for i, test := range testData {
|
||||
in := String(test.in)
|
||||
var out uint64
|
||||
ok := in.ReadASN1Integer(&out)
|
||||
if !ok || out != test.out {
|
||||
t.Errorf("#%d: in.ReadASN1Integer() = %v, want true; out = %d, want %d", i, ok, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1IntegerInvalid(t *testing.T) {
|
||||
testData := []String{
|
||||
[]byte{3, 1, 0}, // invalid tag
|
||||
// truncated
|
||||
[]byte{2, 1},
|
||||
[]byte{2, 2, 0},
|
||||
// not minimally encoded
|
||||
[]byte{2, 2, 0, 1},
|
||||
[]byte{2, 2, 0xff, 0xff},
|
||||
}
|
||||
|
||||
for i, test := range testData {
|
||||
var out int64
|
||||
if test.ReadASN1Integer(&out) {
|
||||
t.Errorf("#%d: in.ReadASN1Integer() = true, want false (out = %d)", i, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1ObjectIdentifier(t *testing.T) {
|
||||
testData := []struct {
|
||||
in []byte
|
||||
ok bool
|
||||
out []int
|
||||
}{
|
||||
{[]byte{}, false, []int{}},
|
||||
{[]byte{6, 0}, false, []int{}},
|
||||
{[]byte{5, 1, 85}, false, []int{2, 5}},
|
||||
{[]byte{6, 1, 85}, true, []int{2, 5}},
|
||||
{[]byte{6, 2, 85, 0x02}, true, []int{2, 5, 2}},
|
||||
{[]byte{6, 4, 85, 0x02, 0xc0, 0x00}, true, []int{2, 5, 2, 0x2000}},
|
||||
{[]byte{6, 3, 0x81, 0x34, 0x03}, true, []int{2, 100, 3}},
|
||||
{[]byte{6, 7, 85, 0x02, 0xc0, 0x80, 0x80, 0x80, 0x80}, false, []int{}},
|
||||
}
|
||||
|
||||
for i, test := range testData {
|
||||
in := String(test.in)
|
||||
var out asn1.ObjectIdentifier
|
||||
ok := in.ReadASN1ObjectIdentifier(&out)
|
||||
if ok != test.ok || ok && !out.Equal(test.out) {
|
||||
t.Errorf("#%d: in.ReadASN1ObjectIdentifier() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1GeneralizedTime(t *testing.T) {
|
||||
testData := []struct {
|
||||
in string
|
||||
ok bool
|
||||
out time.Time
|
||||
}{
|
||||
{"20100102030405Z", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.UTC)},
|
||||
{"20100102030405", false, time.Time{}},
|
||||
{"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
|
||||
{"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
|
||||
/* These are invalid times. However, the time package normalises times
|
||||
* and they were accepted in some versions. See #11134. */
|
||||
{"00000100000000Z", false, time.Time{}},
|
||||
{"20101302030405Z", false, time.Time{}},
|
||||
{"20100002030405Z", false, time.Time{}},
|
||||
{"20100100030405Z", false, time.Time{}},
|
||||
{"20100132030405Z", false, time.Time{}},
|
||||
{"20100231030405Z", false, time.Time{}},
|
||||
{"20100102240405Z", false, time.Time{}},
|
||||
{"20100102036005Z", false, time.Time{}},
|
||||
{"20100102030460Z", false, time.Time{}},
|
||||
{"-20100102030410Z", false, time.Time{}},
|
||||
{"2010-0102030410Z", false, time.Time{}},
|
||||
{"2010-0002030410Z", false, time.Time{}},
|
||||
{"201001-02030410Z", false, time.Time{}},
|
||||
{"20100102-030410Z", false, time.Time{}},
|
||||
{"2010010203-0410Z", false, time.Time{}},
|
||||
{"201001020304-10Z", false, time.Time{}},
|
||||
}
|
||||
for i, test := range testData {
|
||||
in := String(append([]byte{asn1.TagGeneralizedTime, byte(len(test.in))}, test.in...))
|
||||
var out time.Time
|
||||
ok := in.ReadASN1GeneralizedTime(&out)
|
||||
if ok != test.ok || ok && !reflect.DeepEqual(out, test.out) {
|
||||
t.Errorf("#%d: in.ReadASN1GeneralizedTime() = %v, want %v; out = %q, want %q", i, ok, test.ok, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadASN1BitString(t *testing.T) {
|
||||
testData := []struct {
|
||||
in []byte
|
||||
ok bool
|
||||
out asn1.BitString
|
||||
}{
|
||||
{[]byte{}, false, asn1.BitString{}},
|
||||
{[]byte{0x00}, true, asn1.BitString{}},
|
||||
{[]byte{0x07, 0x00}, true, asn1.BitString{Bytes: []byte{0}, BitLength: 1}},
|
||||
{[]byte{0x07, 0x01}, false, asn1.BitString{}},
|
||||
{[]byte{0x07, 0x40}, false, asn1.BitString{}},
|
||||
{[]byte{0x08, 0x00}, false, asn1.BitString{}},
|
||||
{[]byte{0xff}, false, asn1.BitString{}},
|
||||
{[]byte{0xfe, 0x00}, false, asn1.BitString{}},
|
||||
}
|
||||
for i, test := range testData {
|
||||
in := String(append([]byte{3, byte(len(test.in))}, test.in...))
|
||||
var out asn1.BitString
|
||||
ok := in.ReadASN1BitString(&out)
|
||||
if ok != test.ok || ok && (!bytes.Equal(out.Bytes, test.out.Bytes) || out.BitLength != test.out.BitLength) {
|
||||
t.Errorf("#%d: in.ReadASN1BitString() = %v, want %v; out = %v, want %v", i, ok, test.ok, out, test.out)
|
||||
}
|
||||
}
|
||||
}
|
||||
255
vendor/golang.org/x/crypto/cryptobyte/builder.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,255 @@
|
||||
// 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 cryptobyte
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A Builder builds byte strings from fixed-length and length-prefixed values.
|
||||
// The zero value is a usable Builder that allocates space as needed.
|
||||
type Builder struct {
|
||||
err error
|
||||
result []byte
|
||||
fixedSize bool
|
||||
child *Builder
|
||||
offset int
|
||||
pendingLenLen int
|
||||
pendingIsASN1 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 NewBuilder(buffer []byte) *Builder {
|
||||
return &Builder{
|
||||
result: buffer,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 NewFixedBuilder(buffer []byte) *Builder {
|
||||
return &Builder{
|
||||
result: buffer,
|
||||
fixedSize: true,
|
||||
}
|
||||
}
|
||||
|
||||
// Bytes returns the bytes written by the builder or an error if one has
|
||||
// occurred during during building.
|
||||
func (b *Builder) Bytes() ([]byte, error) {
|
||||
if b.err != nil {
|
||||
return nil, b.err
|
||||
}
|
||||
return b.result[b.offset:], nil
|
||||
}
|
||||
|
||||
// BytesOrPanic returns the bytes written by the builder or panics if an error
|
||||
// has occurred during building.
|
||||
func (b *Builder) BytesOrPanic() []byte {
|
||||
if b.err != nil {
|
||||
panic(b.err)
|
||||
}
|
||||
return b.result[b.offset:]
|
||||
}
|
||||
|
||||
// AddUint8 appends an 8-bit value to the byte string.
|
||||
func (b *Builder) AddUint8(v uint8) {
|
||||
b.add(byte(v))
|
||||
}
|
||||
|
||||
// AddUint16 appends a big-endian, 16-bit value to the byte string.
|
||||
func (b *Builder) AddUint16(v uint16) {
|
||||
b.add(byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// 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 (b *Builder) AddUint24(v uint32) {
|
||||
b.add(byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddUint32 appends a big-endian, 32-bit value to the byte string.
|
||||
func (b *Builder) AddUint32(v uint32) {
|
||||
b.add(byte(v>>24), byte(v>>16), byte(v>>8), byte(v))
|
||||
}
|
||||
|
||||
// AddBytes appends a sequence of bytes to the byte string.
|
||||
func (b *Builder) AddBytes(v []byte) {
|
||||
b.add(v...)
|
||||
}
|
||||
|
||||
// BuilderContinuation is 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. 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.
|
||||
type BuilderContinuation func(child *Builder)
|
||||
|
||||
// AddUint8LengthPrefixed adds a 8-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint8LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(1, false, f)
|
||||
}
|
||||
|
||||
// AddUint16LengthPrefixed adds a big-endian, 16-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint16LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(2, false, f)
|
||||
}
|
||||
|
||||
// AddUint24LengthPrefixed adds a big-endian, 24-bit length-prefixed byte sequence.
|
||||
func (b *Builder) AddUint24LengthPrefixed(f BuilderContinuation) {
|
||||
b.addLengthPrefixed(3, false, f)
|
||||
}
|
||||
|
||||
func (b *Builder) addLengthPrefixed(lenLen int, isASN1 bool, f BuilderContinuation) {
|
||||
// Subsequent writes can be ignored if the builder has encountered an error.
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
offset := len(b.result)
|
||||
b.add(make([]byte, lenLen)...)
|
||||
|
||||
b.child = &Builder{
|
||||
result: b.result,
|
||||
fixedSize: b.fixedSize,
|
||||
offset: offset,
|
||||
pendingLenLen: lenLen,
|
||||
pendingIsASN1: isASN1,
|
||||
}
|
||||
|
||||
f(b.child)
|
||||
b.flushChild()
|
||||
if b.child != nil {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) flushChild() {
|
||||
if b.child == nil {
|
||||
return
|
||||
}
|
||||
b.child.flushChild()
|
||||
child := b.child
|
||||
b.child = nil
|
||||
|
||||
if child.err != nil {
|
||||
b.err = child.err
|
||||
return
|
||||
}
|
||||
|
||||
length := len(child.result) - child.pendingLenLen - child.offset
|
||||
|
||||
if length < 0 {
|
||||
panic("cryptobyte: internal error") // result unexpectedly shrunk
|
||||
}
|
||||
|
||||
if child.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 child.pendingLenLen != 1 {
|
||||
panic("cryptobyte: internal error")
|
||||
}
|
||||
var lenLen, lenByte uint8
|
||||
if int64(length) > 0xfffffffe {
|
||||
b.err = errors.New("pending ASN.1 child too long")
|
||||
return
|
||||
} else if length > 0xffffff {
|
||||
lenLen = 5
|
||||
lenByte = 0x80 | 4
|
||||
} else if length > 0xffff {
|
||||
lenLen = 4
|
||||
lenByte = 0x80 | 3
|
||||
} else if length > 0xff {
|
||||
lenLen = 3
|
||||
lenByte = 0x80 | 2
|
||||
} else if length > 0x7f {
|
||||
lenLen = 2
|
||||
lenByte = 0x80 | 1
|
||||
} else {
|
||||
lenLen = 1
|
||||
lenByte = uint8(length)
|
||||
length = 0
|
||||
}
|
||||
|
||||
// Insert the initial length byte, make space for successive length bytes,
|
||||
// and adjust the offset.
|
||||
child.result[child.offset] = lenByte
|
||||
extraBytes := int(lenLen - 1)
|
||||
if extraBytes != 0 {
|
||||
child.add(make([]byte, extraBytes)...)
|
||||
childStart := child.offset + child.pendingLenLen
|
||||
copy(child.result[childStart+extraBytes:], child.result[childStart:])
|
||||
}
|
||||
child.offset++
|
||||
child.pendingLenLen = extraBytes
|
||||
}
|
||||
|
||||
l := length
|
||||
for i := child.pendingLenLen - 1; i >= 0; i-- {
|
||||
child.result[child.offset+i] = uint8(l)
|
||||
l >>= 8
|
||||
}
|
||||
if l != 0 {
|
||||
b.err = fmt.Errorf("cryptobyte: pending child length %d exceeds %d-byte length prefix", length, child.pendingLenLen)
|
||||
return
|
||||
}
|
||||
|
||||
if !b.fixedSize {
|
||||
b.result = child.result // In case child reallocated result.
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Builder) add(bytes ...byte) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
if b.child != nil {
|
||||
panic("attempted write while child is pending")
|
||||
}
|
||||
if len(b.result)+len(bytes) < len(bytes) {
|
||||
b.err = errors.New("cryptobyte: length overflow")
|
||||
}
|
||||
if b.fixedSize && len(b.result)+len(bytes) > cap(b.result) {
|
||||
b.err = errors.New("cryptobyte: Builder is exceeding its fixed-size buffer")
|
||||
return
|
||||
}
|
||||
b.result = append(b.result, bytes...)
|
||||
}
|
||||
|
||||
// A MarshalingValue marshals itself into a Builder.
|
||||
type MarshalingValue interface {
|
||||
// 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 (b *Builder) AddValue(v MarshalingValue) {
|
||||
err := v.Marshal(b)
|
||||
if err != nil {
|
||||
b.err = err
|
||||
}
|
||||
}
|
||||
379
vendor/golang.org/x/crypto/cryptobyte/cryptobyte_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,379 @@
|
||||
// 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 cryptobyte
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func builderBytesEq(b *Builder, want ...byte) error {
|
||||
got := b.BytesOrPanic()
|
||||
if !bytes.Equal(got, want) {
|
||||
return fmt.Errorf("Bytes() = %v, want %v", got, want)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestBytes(t *testing.T) {
|
||||
var b Builder
|
||||
v := []byte("foobarbaz")
|
||||
b.AddBytes(v[0:3])
|
||||
b.AddBytes(v[3:4])
|
||||
b.AddBytes(v[4:9])
|
||||
if err := builderBytesEq(&b, v...); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
s := String(b.BytesOrPanic())
|
||||
for _, w := range []string{"foo", "bar", "baz"} {
|
||||
var got []byte
|
||||
if !s.ReadBytes(&got, 3) {
|
||||
t.Errorf("ReadBytes() = false, want true (w = %v)", w)
|
||||
}
|
||||
want := []byte(w)
|
||||
if !bytes.Equal(got, want) {
|
||||
t.Errorf("ReadBytes(): got = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint8(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8(42)
|
||||
if err := builderBytesEq(&b, 42); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s String = b.BytesOrPanic()
|
||||
var v uint8
|
||||
if !s.ReadUint8(&v) {
|
||||
t.Error("ReadUint8() = false, want true")
|
||||
}
|
||||
if v != 42 {
|
||||
t.Errorf("v = %d, want 42", v)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint16(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint16(65534)
|
||||
if err := builderBytesEq(&b, 255, 254); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
var s String = b.BytesOrPanic()
|
||||
var v uint16
|
||||
if !s.ReadUint16(&v) {
|
||||
t.Error("ReadUint16() == false, want true")
|
||||
}
|
||||
if v != 65534 {
|
||||
t.Errorf("v = %d, want 65534", v)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint24(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint24(0xfffefd)
|
||||
if err := builderBytesEq(&b, 255, 254, 253); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s String = b.BytesOrPanic()
|
||||
var v uint32
|
||||
if !s.ReadUint24(&v) {
|
||||
t.Error("ReadUint8() = false, want true")
|
||||
}
|
||||
if v != 0xfffefd {
|
||||
t.Errorf("v = %d, want fffefd", v)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint24Truncation(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint24(0x10111213)
|
||||
if err := builderBytesEq(&b, 0x11, 0x12, 0x13); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint32(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint32(0xfffefdfc)
|
||||
if err := builderBytesEq(&b, 255, 254, 253, 252); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s String = b.BytesOrPanic()
|
||||
var v uint32
|
||||
if !s.ReadUint32(&v) {
|
||||
t.Error("ReadUint8() = false, want true")
|
||||
}
|
||||
if v != 0xfffefdfc {
|
||||
t.Errorf("v = %x, want fffefdfc", v)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUMultiple(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8(23)
|
||||
b.AddUint32(0xfffefdfc)
|
||||
b.AddUint16(42)
|
||||
if err := builderBytesEq(&b, 23, 255, 254, 253, 252, 0, 42); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s String = b.BytesOrPanic()
|
||||
var (
|
||||
x uint8
|
||||
y uint32
|
||||
z uint16
|
||||
)
|
||||
if !s.ReadUint8(&x) || !s.ReadUint32(&y) || !s.ReadUint16(&z) {
|
||||
t.Error("ReadUint8() = false, want true")
|
||||
}
|
||||
if x != 23 || y != 0xfffefdfc || z != 42 {
|
||||
t.Errorf("x, y, z = %d, %d, %d; want 23, 4294901244, 5", x, y, z)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint8LengthPrefixedSimple(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(23)
|
||||
c.AddUint8(42)
|
||||
})
|
||||
if err := builderBytesEq(&b, 2, 23, 42); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var base, child String = b.BytesOrPanic(), nil
|
||||
var x, y uint8
|
||||
if !base.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) ||
|
||||
!child.ReadUint8(&y) {
|
||||
t.Error("parsing failed")
|
||||
}
|
||||
if x != 23 || y != 42 {
|
||||
t.Errorf("want x, y == 23, 42; got %d, %d", x, y)
|
||||
}
|
||||
if len(base) != 0 {
|
||||
t.Errorf("len(base) = %d, want 0", len(base))
|
||||
}
|
||||
if len(child) != 0 {
|
||||
t.Errorf("len(child) = %d, want 0", len(child))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint8LengthPrefixedMulti(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(23)
|
||||
c.AddUint8(42)
|
||||
})
|
||||
b.AddUint8(5)
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(123)
|
||||
c.AddUint8(234)
|
||||
})
|
||||
if err := builderBytesEq(&b, 2, 23, 42, 5, 2, 123, 234); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var s, child String = b.BytesOrPanic(), nil
|
||||
var u, v, w, x, y uint8
|
||||
if !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&u) || !child.ReadUint8(&v) ||
|
||||
!s.ReadUint8(&w) || !s.ReadUint8LengthPrefixed(&child) || !child.ReadUint8(&x) || !child.ReadUint8(&y) {
|
||||
t.Error("parsing failed")
|
||||
}
|
||||
if u != 23 || v != 42 || w != 5 || x != 123 || y != 234 {
|
||||
t.Errorf("u, v, w, x, y = %d, %d, %d, %d, %d; want 23, 42, 5, 123, 234",
|
||||
u, v, w, x, y)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
if len(child) != 0 {
|
||||
t.Errorf("len(child) = %d, want 0", len(child))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUint8LengthPrefixedNested(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(5)
|
||||
c.AddUint8LengthPrefixed(func(d *Builder) {
|
||||
d.AddUint8(23)
|
||||
d.AddUint8(42)
|
||||
})
|
||||
c.AddUint8(123)
|
||||
})
|
||||
if err := builderBytesEq(&b, 5, 5, 2, 23, 42, 123); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
var base, child1, child2 String = b.BytesOrPanic(), nil, nil
|
||||
var u, v, w, x uint8
|
||||
if !base.ReadUint8LengthPrefixed(&child1) {
|
||||
t.Error("parsing base failed")
|
||||
}
|
||||
if !child1.ReadUint8(&u) || !child1.ReadUint8LengthPrefixed(&child2) || !child1.ReadUint8(&x) {
|
||||
t.Error("parsing child1 failed")
|
||||
}
|
||||
if !child2.ReadUint8(&v) || !child2.ReadUint8(&w) {
|
||||
t.Error("parsing child2 failed")
|
||||
}
|
||||
if u != 5 || v != 23 || w != 42 || x != 123 {
|
||||
t.Errorf("u, v, w, x = %d, %d, %d, %d, want 5, 23, 42, 123",
|
||||
u, v, w, x)
|
||||
}
|
||||
if len(base) != 0 {
|
||||
t.Errorf("len(base) = %d, want 0", len(base))
|
||||
}
|
||||
if len(child1) != 0 {
|
||||
t.Errorf("len(child1) = %d, want 0", len(child1))
|
||||
}
|
||||
if len(base) != 0 {
|
||||
t.Errorf("len(child2) = %d, want 0", len(child2))
|
||||
}
|
||||
}
|
||||
|
||||
func TestPreallocatedBuffer(t *testing.T) {
|
||||
var buf [5]byte
|
||||
b := NewBuilder(buf[0:0])
|
||||
b.AddUint8(1)
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8(3)
|
||||
c.AddUint8(4)
|
||||
})
|
||||
b.AddUint16(1286) // Outgrow buf by one byte.
|
||||
want := []byte{1, 2, 3, 4, 0}
|
||||
if !bytes.Equal(buf[:], want) {
|
||||
t.Errorf("buf = %v want %v", buf, want)
|
||||
}
|
||||
if err := builderBytesEq(b, 1, 2, 3, 4, 5, 6); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteWithPendingChild(t *testing.T) {
|
||||
var b Builder
|
||||
b.AddUint8LengthPrefixed(func(c *Builder) {
|
||||
c.AddUint8LengthPrefixed(func(d *Builder) {
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; c.AddUint8() did not panic")
|
||||
}
|
||||
}()
|
||||
c.AddUint8(2) // panics
|
||||
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
|
||||
}
|
||||
}()
|
||||
b.AddUint8(2) // panics
|
||||
})
|
||||
|
||||
defer func() {
|
||||
if recover() == nil {
|
||||
t.Errorf("recover() = nil, want error; b.AddUint8() did not panic")
|
||||
}
|
||||
}()
|
||||
b.AddUint8(2) // panics
|
||||
})
|
||||
}
|
||||
|
||||
// ASN.1
|
||||
|
||||
func TestASN1Int64(t *testing.T) {
|
||||
tests := []struct {
|
||||
in int64
|
||||
want []byte
|
||||
}{
|
||||
{-0x800000, []byte{2, 3, 128, 0, 0}},
|
||||
{-256, []byte{2, 2, 255, 0}},
|
||||
{-129, []byte{2, 2, 255, 127}},
|
||||
{-128, []byte{2, 1, 128}},
|
||||
{-1, []byte{2, 1, 255}},
|
||||
{0, []byte{2, 1, 0}},
|
||||
{1, []byte{2, 1, 1}},
|
||||
{2, []byte{2, 1, 2}},
|
||||
{127, []byte{2, 1, 127}},
|
||||
{128, []byte{2, 2, 0, 128}},
|
||||
{256, []byte{2, 2, 1, 0}},
|
||||
{0x800000, []byte{2, 4, 0, 128, 0, 0}},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
var b Builder
|
||||
b.AddASN1Int64(tt.in)
|
||||
if err := builderBytesEq(&b, tt.want...); err != nil {
|
||||
t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
|
||||
}
|
||||
|
||||
var n int64
|
||||
s := String(b.BytesOrPanic())
|
||||
ok := s.ReadASN1Integer(&n)
|
||||
if !ok || n != tt.in {
|
||||
t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
|
||||
ok, n, tt.in, i)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestASN1Uint64(t *testing.T) {
|
||||
tests := []struct {
|
||||
in uint64
|
||||
want []byte
|
||||
}{
|
||||
{0, []byte{2, 1, 0}},
|
||||
{1, []byte{2, 1, 1}},
|
||||
{2, []byte{2, 1, 2}},
|
||||
{127, []byte{2, 1, 127}},
|
||||
{128, []byte{2, 2, 0, 128}},
|
||||
{256, []byte{2, 2, 1, 0}},
|
||||
{0x800000, []byte{2, 4, 0, 128, 0, 0}},
|
||||
{0x7fffffffffffffff, []byte{2, 8, 127, 255, 255, 255, 255, 255, 255, 255}},
|
||||
{0x8000000000000000, []byte{2, 9, 0, 128, 0, 0, 0, 0, 0, 0, 0}},
|
||||
{0xffffffffffffffff, []byte{2, 9, 0, 255, 255, 255, 255, 255, 255, 255, 255}},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
var b Builder
|
||||
b.AddASN1Uint64(tt.in)
|
||||
if err := builderBytesEq(&b, tt.want...); err != nil {
|
||||
t.Errorf("%v, (i = %d; in = %v)", err, i, tt.in)
|
||||
}
|
||||
|
||||
var n uint64
|
||||
s := String(b.BytesOrPanic())
|
||||
ok := s.ReadASN1Integer(&n)
|
||||
if !ok || n != tt.in {
|
||||
t.Errorf("s.ReadASN1Integer(&n) = %v, n = %d; want true, n = %d (i = %d)",
|
||||
ok, n, tt.in, i)
|
||||
}
|
||||
if len(s) != 0 {
|
||||
t.Errorf("len(s) = %d, want 0", len(s))
|
||||
}
|
||||
}
|
||||
}
|
||||
120
vendor/golang.org/x/crypto/cryptobyte/example_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,120 @@
|
||||
// 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 cryptobyte_test
|
||||
|
||||
import (
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
)
|
||||
|
||||
func ExampleString_lengthPrefixed() {
|
||||
// This is an example of parsing length-prefixed data (as found in, for
|
||||
// example, TLS). Imagine a 16-bit prefixed series of 8-bit prefixed
|
||||
// strings.
|
||||
|
||||
input := cryptobyte.String([]byte{0, 12, 5, 'h', 'e', 'l', 'l', 'o', 5, 'w', 'o', 'r', 'l', 'd'})
|
||||
var result []string
|
||||
|
||||
var values cryptobyte.String
|
||||
if !input.ReadUint16LengthPrefixed(&values) ||
|
||||
!input.Empty() {
|
||||
panic("bad format")
|
||||
}
|
||||
|
||||
for !values.Empty() {
|
||||
var value cryptobyte.String
|
||||
if !values.ReadUint8LengthPrefixed(&value) {
|
||||
panic("bad format")
|
||||
}
|
||||
|
||||
result = append(result, string(value))
|
||||
}
|
||||
|
||||
// Output: []string{"hello", "world"}
|
||||
fmt.Printf("%#v\n", result)
|
||||
}
|
||||
|
||||
func ExampleString_asn1() {
|
||||
// This is an example of parsing ASN.1 data that looks like:
|
||||
// Foo ::= SEQUENCE {
|
||||
// version [6] INTEGER DEFAULT 0
|
||||
// data OCTET STRING
|
||||
// }
|
||||
|
||||
input := cryptobyte.String([]byte{0x30, 12, 0xa6, 3, 2, 1, 2, 4, 5, 'h', 'e', 'l', 'l', 'o'})
|
||||
|
||||
var (
|
||||
version int64
|
||||
data, inner, versionBytes cryptobyte.String
|
||||
haveVersion bool
|
||||
)
|
||||
if !input.ReadASN1(&inner, cryptobyte.Tag(asn1.TagSequence).Constructed()) ||
|
||||
!input.Empty() ||
|
||||
!inner.ReadOptionalASN1(&versionBytes, &haveVersion, cryptobyte.Tag(6).Constructed().ContextSpecific()) ||
|
||||
(haveVersion && !versionBytes.ReadASN1Integer(&version)) ||
|
||||
(haveVersion && !versionBytes.Empty()) ||
|
||||
!inner.ReadASN1(&data, asn1.TagOctetString) ||
|
||||
!inner.Empty() {
|
||||
panic("bad format")
|
||||
}
|
||||
|
||||
// Output: haveVersion: true, version: 2, data: hello
|
||||
fmt.Printf("haveVersion: %t, version: %d, data: %s\n", haveVersion, version, string(data))
|
||||
}
|
||||
|
||||
func ExampleBuilder_asn1() {
|
||||
// This is an example of building ASN.1 data that looks like:
|
||||
// Foo ::= SEQUENCE {
|
||||
// version [6] INTEGER DEFAULT 0
|
||||
// data OCTET STRING
|
||||
// }
|
||||
|
||||
version := int64(2)
|
||||
data := []byte("hello")
|
||||
const defaultVersion = 0
|
||||
|
||||
var b cryptobyte.Builder
|
||||
b.AddASN1(cryptobyte.Tag(asn1.TagSequence).Constructed(), func(b *cryptobyte.Builder) {
|
||||
if version != defaultVersion {
|
||||
b.AddASN1(cryptobyte.Tag(6).Constructed().ContextSpecific(), func(b *cryptobyte.Builder) {
|
||||
b.AddASN1Int64(version)
|
||||
})
|
||||
}
|
||||
b.AddASN1OctetString(data)
|
||||
})
|
||||
|
||||
result, err := b.Bytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output: 300ca603020102040568656c6c6f
|
||||
fmt.Printf("%x\n", result)
|
||||
}
|
||||
|
||||
func ExampleBuilder_lengthPrefixed() {
|
||||
// This is an example of building length-prefixed data (as found in,
|
||||
// for example, TLS). Imagine a 16-bit prefixed series of 8-bit
|
||||
// prefixed strings.
|
||||
input := []string{"hello", "world"}
|
||||
|
||||
var b cryptobyte.Builder
|
||||
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
for _, value := range input {
|
||||
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
|
||||
b.AddBytes([]byte(value))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
result, err := b.Bytes()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output: 000c0568656c6c6f05776f726c64
|
||||
fmt.Printf("%x\n", result)
|
||||
}
|
||||
157
vendor/golang.org/x/crypto/cryptobyte/string.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,157 @@
|
||||
// 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 cryptobyte implements building and parsing of byte strings for
|
||||
// DER-encoded ASN.1 and TLS messages. See the examples for the Builder and
|
||||
// String types to get started.
|
||||
package cryptobyte
|
||||
|
||||
// String represents a string of bytes. It provides methods for parsing
|
||||
// fixed-length and length-prefixed values from it.
|
||||
type String []byte
|
||||
|
||||
// read advances a String by n bytes and returns them. If less than n bytes
|
||||
// remain, it returns nil.
|
||||
func (s *String) read(n int) []byte {
|
||||
if len(*s) < n {
|
||||
return nil
|
||||
}
|
||||
v := (*s)[:n]
|
||||
*s = (*s)[n:]
|
||||
return v
|
||||
}
|
||||
|
||||
// Skip advances the String by n byte and reports whether it was successful.
|
||||
func (s *String) Skip(n int) bool {
|
||||
return s.read(n) != nil
|
||||
}
|
||||
|
||||
// ReadUint8 decodes an 8-bit value into out and advances over it. It
|
||||
// returns true on success and false on error.
|
||||
func (s *String) ReadUint8(out *uint8) bool {
|
||||
v := s.read(1)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint8(v[0])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint16 decodes a big-endian, 16-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
func (s *String) ReadUint16(out *uint16) bool {
|
||||
v := s.read(2)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint16(v[0])<<8 | uint16(v[1])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint24 decodes a big-endian, 24-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
func (s *String) ReadUint24(out *uint32) bool {
|
||||
v := s.read(3)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint32(v[0])<<16 | uint32(v[1])<<8 | uint32(v[2])
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint32 decodes a big-endian, 32-bit value into out and advances over it.
|
||||
// It returns true on success and false on error.
|
||||
func (s *String) ReadUint32(out *uint32) bool {
|
||||
v := s.read(4)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = uint32(v[0])<<24 | uint32(v[1])<<16 | uint32(v[2])<<8 | uint32(v[3])
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readUnsigned(out *uint32, length int) bool {
|
||||
v := s.read(length)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
var result uint32
|
||||
for i := 0; i < length; i++ {
|
||||
result <<= 8
|
||||
result |= uint32(v[i])
|
||||
}
|
||||
*out = result
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *String) readLengthPrefixed(lenLen int, outChild *String) bool {
|
||||
lenBytes := s.read(lenLen)
|
||||
if lenBytes == nil {
|
||||
return false
|
||||
}
|
||||
var length uint32
|
||||
for _, b := range lenBytes {
|
||||
length = length << 8
|
||||
length = length | uint32(b)
|
||||
}
|
||||
if int(length) < 0 {
|
||||
// This currently cannot overflow because we read uint24 at most, but check
|
||||
// anyway in case that changes in the future.
|
||||
return false
|
||||
}
|
||||
v := s.read(int(length))
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*outChild = v
|
||||
return true
|
||||
}
|
||||
|
||||
// ReadUint8LengthPrefixed reads the content of an 8-bit length-prefixed value
|
||||
// into out and advances over it. It returns true on success and false on
|
||||
// error.
|
||||
func (s *String) ReadUint8LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(1, out)
|
||||
}
|
||||
|
||||
// ReadUint16LengthPrefixed reads the content of a big-endian, 16-bit
|
||||
// length-prefixed value into out and advances over it. It returns true on
|
||||
// success and false on error.
|
||||
func (s *String) ReadUint16LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(2, out)
|
||||
}
|
||||
|
||||
// ReadUint24LengthPrefixed reads the content of a big-endian, 24-bit
|
||||
// length-prefixed value into out and advances over it. It returns true on
|
||||
// success and false on error.
|
||||
func (s *String) ReadUint24LengthPrefixed(out *String) bool {
|
||||
return s.readLengthPrefixed(3, out)
|
||||
}
|
||||
|
||||
// ReadBytes reads n bytes into out and advances over them. It returns true on
|
||||
// success and false and error.
|
||||
func (s *String) ReadBytes(out *[]byte, n int) bool {
|
||||
v := s.read(n)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
*out = v
|
||||
return true
|
||||
}
|
||||
|
||||
// CopyBytes copies len(out) bytes into out and advances over them. It returns
|
||||
// true on success and false on error.
|
||||
func (s *String) CopyBytes(out []byte) bool {
|
||||
n := len(out)
|
||||
v := s.read(n)
|
||||
if v == nil {
|
||||
return false
|
||||
}
|
||||
return copy(out, v) == n
|
||||
}
|
||||
|
||||
// Empty reports whether the string does not contain any bytes.
|
||||
func (s String) Empty() bool {
|
||||
return len(s) == 0
|
||||
}
|
||||
8
vendor/golang.org/x/crypto/curve25519/const_amd64.h
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,8 @@
|
||||
// Copyright 2012 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.
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: http://bench.cr.yp.to/supercop.html
|
||||
|
||||
#define REDMASK51 0x0007FFFFFFFFFFFF
|
||||
4
vendor/golang.org/x/crypto/curve25519/const_amd64.s
сгенерированный
поставляемый
@@ -7,8 +7,8 @@
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
DATA ·REDMASK51(SB)/8, $0x0007FFFFFFFFFFFF
|
||||
GLOBL ·REDMASK51(SB), 8, $8
|
||||
// These constants cannot be encoded in non-MOVQ immediates.
|
||||
// We access them directly from memory instead.
|
||||
|
||||
DATA ·_121666_213(SB)/8, $996687872
|
||||
GLOBL ·_121666_213(SB), 8, $8
|
||||
|
||||
4
vendor/golang.org/x/crypto/curve25519/freeze_amd64.s
сгенерированный
поставляемый
@@ -7,6 +7,8 @@
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "const_amd64.h"
|
||||
|
||||
// func freeze(inout *[5]uint64)
|
||||
TEXT ·freeze(SB),7,$0-8
|
||||
MOVQ inout+0(FP), DI
|
||||
@@ -16,7 +18,7 @@ TEXT ·freeze(SB),7,$0-8
|
||||
MOVQ 16(DI),CX
|
||||
MOVQ 24(DI),R8
|
||||
MOVQ 32(DI),R9
|
||||
MOVQ ·REDMASK51(SB),AX
|
||||
MOVQ $REDMASK51,AX
|
||||
MOVQ AX,R10
|
||||
SUBQ $18,R10
|
||||
MOVQ $3,R11
|
||||
|
||||
20
vendor/golang.org/x/crypto/curve25519/ladderstep_amd64.s
сгенерированный
поставляемый
@@ -7,6 +7,8 @@
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "const_amd64.h"
|
||||
|
||||
// func ladderstep(inout *[5][5]uint64)
|
||||
TEXT ·ladderstep(SB),0,$296-8
|
||||
MOVQ inout+0(FP),DI
|
||||
@@ -118,7 +120,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 72(SP)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
@@ -233,7 +235,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 32(SP)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
@@ -438,7 +440,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 72(SP)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
@@ -588,7 +590,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 32(SP)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
@@ -728,7 +730,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 152(DI)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
@@ -843,7 +845,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 192(DI)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
@@ -993,7 +995,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 32(DI)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
@@ -1143,7 +1145,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 112(SP)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
@@ -1329,7 +1331,7 @@ TEXT ·ladderstep(SB),0,$296-8
|
||||
MULQ 192(SP)
|
||||
ADDQ AX,R12
|
||||
ADCQ DX,R13
|
||||
MOVQ ·REDMASK51(SB),DX
|
||||
MOVQ $REDMASK51,DX
|
||||
SHLQ $13,CX:SI
|
||||
ANDQ DX,SI
|
||||
SHLQ $13,R9:R8
|
||||
|
||||
4
vendor/golang.org/x/crypto/curve25519/mul_amd64.s
сгенерированный
поставляемый
@@ -7,6 +7,8 @@
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "const_amd64.h"
|
||||
|
||||
// func mul(dest, a, b *[5]uint64)
|
||||
TEXT ·mul(SB),0,$16-24
|
||||
MOVQ dest+0(FP), DI
|
||||
@@ -121,7 +123,7 @@ TEXT ·mul(SB),0,$16-24
|
||||
MULQ 32(CX)
|
||||
ADDQ AX,R14
|
||||
ADCQ DX,R15
|
||||
MOVQ ·REDMASK51(SB),SI
|
||||
MOVQ $REDMASK51,SI
|
||||
SHLQ $13,R9:R8
|
||||
ANDQ SI,R8
|
||||
SHLQ $13,R11:R10
|
||||
|
||||
4
vendor/golang.org/x/crypto/curve25519/square_amd64.s
сгенерированный
поставляемый
@@ -7,6 +7,8 @@
|
||||
|
||||
// +build amd64,!gccgo,!appengine
|
||||
|
||||
#include "const_amd64.h"
|
||||
|
||||
// func square(out, in *[5]uint64)
|
||||
TEXT ·square(SB),7,$0-16
|
||||
MOVQ out+0(FP), DI
|
||||
@@ -84,7 +86,7 @@ TEXT ·square(SB),7,$0-16
|
||||
MULQ 32(SI)
|
||||
ADDQ AX,R13
|
||||
ADCQ DX,R14
|
||||
MOVQ ·REDMASK51(SB),SI
|
||||
MOVQ $REDMASK51,SI
|
||||
SHLQ $13,R8:CX
|
||||
ANDQ SI,CX
|
||||
SHLQ $13,R10:R9
|
||||
|
||||
6
vendor/golang.org/x/crypto/ocsp/ocsp_test.go
сгенерированный
поставляемый
@@ -225,7 +225,6 @@ func TestOCSPResponse(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
producedAt := time.Now().Truncate(time.Minute)
|
||||
thisUpdate := time.Date(2010, 7, 7, 15, 1, 5, 0, time.UTC)
|
||||
nextUpdate := time.Date(2010, 7, 7, 18, 35, 17, 0, time.UTC)
|
||||
template := Response{
|
||||
@@ -284,8 +283,9 @@ func TestOCSPResponse(t *testing.T) {
|
||||
t.Errorf("resp.Extensions: got %v, want %v", resp.Extensions, template.ExtraExtensions)
|
||||
}
|
||||
|
||||
if !resp.ProducedAt.Equal(producedAt) {
|
||||
t.Errorf("resp.ProducedAt: got %d, want %d", resp.ProducedAt, producedAt)
|
||||
delay := time.Since(resp.ProducedAt)
|
||||
if delay < -time.Hour || delay > time.Hour {
|
||||
t.Errorf("resp.ProducedAt: got %s, want close to current time (%s)", resp.ProducedAt, time.Now())
|
||||
}
|
||||
|
||||
if resp.Status != template.Status {
|
||||
|
||||
37
vendor/golang.org/x/crypto/poly1305/poly1305_test.go
сгенерированный
поставляемый
@@ -6,10 +6,14 @@ package poly1305
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"flag"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var stressFlag = flag.Bool("stress", false, "run slow stress tests")
|
||||
|
||||
var testData = []struct {
|
||||
in, k, correct []byte
|
||||
}{
|
||||
@@ -88,6 +92,39 @@ func testSum(t *testing.T, unaligned bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBurnin(t *testing.T) {
|
||||
// This test can be used to sanity-check significant changes. It can
|
||||
// take about many minutes to run, even on fast machines. It's disabled
|
||||
// by default.
|
||||
if !*stressFlag {
|
||||
t.Skip("skipping without -stress")
|
||||
}
|
||||
|
||||
var key [32]byte
|
||||
var input [25]byte
|
||||
var output [16]byte
|
||||
|
||||
for i := range key {
|
||||
key[i] = 1
|
||||
}
|
||||
for i := range input {
|
||||
input[i] = 2
|
||||
}
|
||||
|
||||
for i := uint64(0); i < 1e10; i++ {
|
||||
Sum(&output, input[:], &key)
|
||||
copy(key[0:], output[:])
|
||||
copy(key[16:], output[:])
|
||||
copy(input[:], output[:])
|
||||
copy(input[16:], output[:])
|
||||
}
|
||||
|
||||
const expected = "5e3b866aea0b636d240c83c428f84bfa"
|
||||
if got := hex.EncodeToString(output[:]); got != expected {
|
||||
t.Errorf("expected %s, got %s", expected, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSum(t *testing.T) { testSum(t, false) }
|
||||
func TestSumUnaligned(t *testing.T) { testSum(t, true) }
|
||||
|
||||
|
||||
1614
vendor/golang.org/x/crypto/poly1305/sum_ref.go
сгенерированный
поставляемый
2
vendor/golang.org/x/crypto/ssh/agent/client_test.go
сгенерированный
поставляемый
@@ -180,7 +180,7 @@ func TestCert(t *testing.T) {
|
||||
// therefore is buffered (net.Pipe deadlocks if both sides start with
|
||||
// a write.)
|
||||
func netPipe() (net.Conn, net.Conn, error) {
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
64
vendor/golang.org/x/crypto/ssh/cipher.go
сгенерированный
поставляемый
@@ -135,6 +135,7 @@ const prefixLen = 5
|
||||
type streamPacketCipher struct {
|
||||
mac hash.Hash
|
||||
cipher cipher.Stream
|
||||
etm bool
|
||||
|
||||
// The following members are to avoid per-packet allocations.
|
||||
prefix [prefixLen]byte
|
||||
@@ -150,7 +151,14 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
||||
var encryptedPaddingLength [1]byte
|
||||
if s.mac != nil && s.etm {
|
||||
copy(encryptedPaddingLength[:], s.prefix[4:5])
|
||||
s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
|
||||
} else {
|
||||
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
||||
}
|
||||
|
||||
length := binary.BigEndian.Uint32(s.prefix[0:4])
|
||||
paddingLength := uint32(s.prefix[4])
|
||||
|
||||
@@ -159,7 +167,12 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
||||
s.mac.Reset()
|
||||
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
||||
s.mac.Write(s.seqNumBytes[:])
|
||||
s.mac.Write(s.prefix[:])
|
||||
if s.etm {
|
||||
s.mac.Write(s.prefix[:4])
|
||||
s.mac.Write(encryptedPaddingLength[:])
|
||||
} else {
|
||||
s.mac.Write(s.prefix[:])
|
||||
}
|
||||
macSize = uint32(s.mac.Size())
|
||||
}
|
||||
|
||||
@@ -184,10 +197,17 @@ func (s *streamPacketCipher) readPacket(seqNum uint32, r io.Reader) ([]byte, err
|
||||
}
|
||||
mac := s.packetData[length-1:]
|
||||
data := s.packetData[:length-1]
|
||||
|
||||
if s.mac != nil && s.etm {
|
||||
s.mac.Write(data)
|
||||
}
|
||||
|
||||
s.cipher.XORKeyStream(data, data)
|
||||
|
||||
if s.mac != nil {
|
||||
s.mac.Write(data)
|
||||
if !s.etm {
|
||||
s.mac.Write(data)
|
||||
}
|
||||
s.macResult = s.mac.Sum(s.macResult[:0])
|
||||
if subtle.ConstantTimeCompare(s.macResult, mac) != 1 {
|
||||
return nil, errors.New("ssh: MAC failure")
|
||||
@@ -203,7 +223,13 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea
|
||||
return errors.New("ssh: packet too large")
|
||||
}
|
||||
|
||||
paddingLength := packetSizeMultiple - (prefixLen+len(packet))%packetSizeMultiple
|
||||
aadlen := 0
|
||||
if s.mac != nil && s.etm {
|
||||
// packet length is not encrypted for EtM modes
|
||||
aadlen = 4
|
||||
}
|
||||
|
||||
paddingLength := packetSizeMultiple - (prefixLen+len(packet)-aadlen)%packetSizeMultiple
|
||||
if paddingLength < 4 {
|
||||
paddingLength += packetSizeMultiple
|
||||
}
|
||||
@@ -220,15 +246,37 @@ func (s *streamPacketCipher) writePacket(seqNum uint32, w io.Writer, rand io.Rea
|
||||
s.mac.Reset()
|
||||
binary.BigEndian.PutUint32(s.seqNumBytes[:], seqNum)
|
||||
s.mac.Write(s.seqNumBytes[:])
|
||||
|
||||
if s.etm {
|
||||
// For EtM algorithms, the packet length must stay unencrypted,
|
||||
// but the following data (padding length) must be encrypted
|
||||
s.cipher.XORKeyStream(s.prefix[4:5], s.prefix[4:5])
|
||||
}
|
||||
|
||||
s.mac.Write(s.prefix[:])
|
||||
|
||||
if !s.etm {
|
||||
// For non-EtM algorithms, the algorithm is applied on unencrypted data
|
||||
s.mac.Write(packet)
|
||||
s.mac.Write(padding)
|
||||
}
|
||||
}
|
||||
|
||||
if !(s.mac != nil && s.etm) {
|
||||
// For EtM algorithms, the padding length has already been encrypted
|
||||
// and the packet length must remain unencrypted
|
||||
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
||||
}
|
||||
|
||||
s.cipher.XORKeyStream(packet, packet)
|
||||
s.cipher.XORKeyStream(padding, padding)
|
||||
|
||||
if s.mac != nil && s.etm {
|
||||
// For EtM algorithms, packet and padding must be encrypted
|
||||
s.mac.Write(packet)
|
||||
s.mac.Write(padding)
|
||||
}
|
||||
|
||||
s.cipher.XORKeyStream(s.prefix[:], s.prefix[:])
|
||||
s.cipher.XORKeyStream(packet, packet)
|
||||
s.cipher.XORKeyStream(padding, padding)
|
||||
|
||||
if _, err := w.Write(s.prefix[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
62
vendor/golang.org/x/crypto/ssh/cipher_test.go
сгенерированный
поставляемый
@@ -26,39 +26,41 @@ func TestPacketCiphers(t *testing.T) {
|
||||
defer delete(cipherModes, aes128cbcID)
|
||||
|
||||
for cipher := range cipherModes {
|
||||
kr := &kexResult{Hash: crypto.SHA1}
|
||||
algs := directionAlgorithms{
|
||||
Cipher: cipher,
|
||||
MAC: "hmac-sha1",
|
||||
Compression: "none",
|
||||
}
|
||||
client, err := newPacketCipher(clientKeys, algs, kr)
|
||||
if err != nil {
|
||||
t.Errorf("newPacketCipher(client, %q): %v", cipher, err)
|
||||
continue
|
||||
}
|
||||
server, err := newPacketCipher(clientKeys, algs, kr)
|
||||
if err != nil {
|
||||
t.Errorf("newPacketCipher(client, %q): %v", cipher, err)
|
||||
continue
|
||||
}
|
||||
for mac := range macModes {
|
||||
kr := &kexResult{Hash: crypto.SHA1}
|
||||
algs := directionAlgorithms{
|
||||
Cipher: cipher,
|
||||
MAC: mac,
|
||||
Compression: "none",
|
||||
}
|
||||
client, err := newPacketCipher(clientKeys, algs, kr)
|
||||
if err != nil {
|
||||
t.Errorf("newPacketCipher(client, %q, %q): %v", cipher, mac, err)
|
||||
continue
|
||||
}
|
||||
server, err := newPacketCipher(clientKeys, algs, kr)
|
||||
if err != nil {
|
||||
t.Errorf("newPacketCipher(client, %q, %q): %v", cipher, mac, err)
|
||||
continue
|
||||
}
|
||||
|
||||
want := "bla bla"
|
||||
input := []byte(want)
|
||||
buf := &bytes.Buffer{}
|
||||
if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
|
||||
t.Errorf("writePacket(%q): %v", cipher, err)
|
||||
continue
|
||||
}
|
||||
want := "bla bla"
|
||||
input := []byte(want)
|
||||
buf := &bytes.Buffer{}
|
||||
if err := client.writePacket(0, buf, rand.Reader, input); err != nil {
|
||||
t.Errorf("writePacket(%q, %q): %v", cipher, mac, err)
|
||||
continue
|
||||
}
|
||||
|
||||
packet, err := server.readPacket(0, buf)
|
||||
if err != nil {
|
||||
t.Errorf("readPacket(%q): %v", cipher, err)
|
||||
continue
|
||||
}
|
||||
packet, err := server.readPacket(0, buf)
|
||||
if err != nil {
|
||||
t.Errorf("readPacket(%q, %q): %v", cipher, mac, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if string(packet) != want {
|
||||
t.Errorf("roundtrip(%q): got %q, want %q", cipher, packet, want)
|
||||
if string(packet) != want {
|
||||
t.Errorf("roundtrip(%q, %q): got %q, want %q", cipher, mac, packet, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
4
vendor/golang.org/x/crypto/ssh/client_auth_test.go
сгенерированный
поставляемый
@@ -333,14 +333,14 @@ func TestClientLoginCert(t *testing.T) {
|
||||
}
|
||||
|
||||
// allowed source address
|
||||
cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24"}
|
||||
cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42/24,::42/120"}
|
||||
cert.SignCert(rand.Reader, testSigners["ecdsa"])
|
||||
if err := tryAuth(t, clientConfig); err != nil {
|
||||
t.Errorf("cert login with source-address failed: %v", err)
|
||||
}
|
||||
|
||||
// disallowed source address
|
||||
cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42"}
|
||||
cert.CriticalOptions = map[string]string{"source-address": "127.0.0.42,::42"}
|
||||
cert.SignCert(rand.Reader, testSigners["ecdsa"])
|
||||
if err := tryAuth(t, clientConfig); err == nil {
|
||||
t.Errorf("cert login with source-address succeeded")
|
||||
|
||||
2
vendor/golang.org/x/crypto/ssh/common.go
сгенерированный
поставляемый
@@ -56,7 +56,7 @@ var supportedHostKeyAlgos = []string{
|
||||
// This is based on RFC 4253, section 6.4, but with hmac-md5 variants removed
|
||||
// because they have reached the end of their useful life.
|
||||
var supportedMACs = []string{
|
||||
"hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
|
||||
"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1", "hmac-sha1-96",
|
||||
}
|
||||
|
||||
var supportedCompressions = []string{compressionNone}
|
||||
|
||||
49
vendor/golang.org/x/crypto/ssh/handshake.go
сгенерированный
поставляемый
@@ -66,8 +66,8 @@ type handshakeTransport struct {
|
||||
|
||||
// If the read loop wants to schedule a kex, it pings this
|
||||
// channel, and the write loop will send out a kex
|
||||
// message. The boolean is whether this is the first request or not.
|
||||
requestKex chan bool
|
||||
// message.
|
||||
requestKex chan struct{}
|
||||
|
||||
// If the other side requests or confirms a kex, its kexInit
|
||||
// packet is sent here for the write loop to find it.
|
||||
@@ -102,14 +102,14 @@ func newHandshakeTransport(conn keyingTransport, config *Config, clientVersion,
|
||||
serverVersion: serverVersion,
|
||||
clientVersion: clientVersion,
|
||||
incoming: make(chan []byte, chanSize),
|
||||
requestKex: make(chan bool, 1),
|
||||
requestKex: make(chan struct{}, 1),
|
||||
startKex: make(chan *pendingKex, 1),
|
||||
|
||||
config: config,
|
||||
}
|
||||
|
||||
// We always start with a mandatory key exchange.
|
||||
t.requestKex <- true
|
||||
t.requestKex <- struct{}{}
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -166,6 +166,7 @@ func (t *handshakeTransport) printPacket(p []byte, write bool) {
|
||||
if write {
|
||||
action = "sent"
|
||||
}
|
||||
|
||||
if p[0] == msgChannelData || p[0] == msgChannelExtendedData {
|
||||
log.Printf("%s %s data (packet %d bytes)", t.id(), action, len(p))
|
||||
} else {
|
||||
@@ -230,14 +231,13 @@ func (t *handshakeTransport) recordWriteError(err error) {
|
||||
|
||||
func (t *handshakeTransport) requestKeyExchange() {
|
||||
select {
|
||||
case t.requestKex <- false:
|
||||
case t.requestKex <- struct{}{}:
|
||||
default:
|
||||
// something already requested a kex, so do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
func (t *handshakeTransport) kexLoop() {
|
||||
firstSent := false
|
||||
|
||||
write:
|
||||
for t.getWriteError() == nil {
|
||||
@@ -251,18 +251,8 @@ write:
|
||||
if !ok {
|
||||
break write
|
||||
}
|
||||
case requestFirst := <-t.requestKex:
|
||||
// For the first key exchange, both
|
||||
// sides will initiate a key exchange,
|
||||
// and both channels will fire. To
|
||||
// avoid doing two key exchanges in a
|
||||
// row, ignore our own request for an
|
||||
// initial kex if we have already sent
|
||||
// it out.
|
||||
if firstSent && requestFirst {
|
||||
|
||||
continue
|
||||
}
|
||||
case <-t.requestKex:
|
||||
break
|
||||
}
|
||||
|
||||
if !sent {
|
||||
@@ -270,7 +260,6 @@ write:
|
||||
t.recordWriteError(err)
|
||||
break
|
||||
}
|
||||
firstSent = true
|
||||
sent = true
|
||||
}
|
||||
}
|
||||
@@ -287,7 +276,8 @@ write:
|
||||
|
||||
// We're not servicing t.startKex, but the remote end
|
||||
// has just sent us a kexInitMsg, so it can't send
|
||||
// another key change request.
|
||||
// another key change request, until we close the done
|
||||
// channel on the pendingKex request.
|
||||
|
||||
err := t.enterKeyExchange(request.otherInit)
|
||||
|
||||
@@ -301,6 +291,23 @@ write:
|
||||
} else if t.algorithms != nil {
|
||||
t.writeBytesLeft = t.algorithms.w.rekeyBytes()
|
||||
}
|
||||
|
||||
// we have completed the key exchange. Since the
|
||||
// reader is still blocked, it is safe to clear out
|
||||
// the requestKex channel. This avoids the situation
|
||||
// where: 1) we consumed our own request for the
|
||||
// initial kex, and 2) the kex from the remote side
|
||||
// caused another send on the requestKex channel,
|
||||
clear:
|
||||
for {
|
||||
select {
|
||||
case <-t.requestKex:
|
||||
//
|
||||
default:
|
||||
break clear
|
||||
}
|
||||
}
|
||||
|
||||
request.done <- t.writeError
|
||||
|
||||
// kex finished. Push packets that we received while
|
||||
@@ -314,7 +321,7 @@ write:
|
||||
break
|
||||
}
|
||||
}
|
||||
t.pendingPackets = t.pendingPackets[0:]
|
||||
t.pendingPackets = t.pendingPackets[:0]
|
||||
t.mu.Unlock()
|
||||
}
|
||||
|
||||
|
||||
61
vendor/golang.org/x/crypto/ssh/handshake_test.go
сгенерированный
поставляемый
@@ -40,7 +40,7 @@ func (t *testChecker) Check(dialAddr string, addr net.Addr, key PublicKey) error
|
||||
// therefore is buffered (net.Pipe deadlocks if both sides start with
|
||||
// a write.)
|
||||
func netPipe() (net.Conn, net.Conn, error) {
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -125,7 +125,12 @@ func TestHandshakeBasic(t *testing.T) {
|
||||
t.Skip("see golang.org/issue/7237")
|
||||
}
|
||||
|
||||
checker := &syncChecker{make(chan int, 10)}
|
||||
checker := &syncChecker{
|
||||
waitCall: make(chan int, 10),
|
||||
called: make(chan int, 10),
|
||||
}
|
||||
|
||||
checker.waitCall <- 1
|
||||
trC, trS, err := handshakePair(&ClientConfig{HostKeyCallback: checker.Check}, "addr", false)
|
||||
if err != nil {
|
||||
t.Fatalf("handshakePair: %v", err)
|
||||
@@ -134,22 +139,25 @@ func TestHandshakeBasic(t *testing.T) {
|
||||
defer trC.Close()
|
||||
defer trS.Close()
|
||||
|
||||
// Let first kex complete normally.
|
||||
<-checker.called
|
||||
|
||||
clientDone := make(chan int, 0)
|
||||
gotHalf := make(chan int, 0)
|
||||
const N = 20
|
||||
|
||||
go func() {
|
||||
defer close(clientDone)
|
||||
// Client writes a bunch of stuff, and does a key
|
||||
// change in the middle. This should not confuse the
|
||||
// handshake in progress
|
||||
for i := 0; i < 10; i++ {
|
||||
// handshake in progress. We do this twice, so we test
|
||||
// that the packet buffer is reset correctly.
|
||||
for i := 0; i < N; i++ {
|
||||
p := []byte{msgRequestSuccess, byte(i)}
|
||||
if err := trC.writePacket(p); err != nil {
|
||||
t.Fatalf("sendPacket: %v", err)
|
||||
}
|
||||
if i == 5 {
|
||||
if (i % 10) == 5 {
|
||||
<-gotHalf
|
||||
// halfway through, we request a key change.
|
||||
trC.requestKeyExchange()
|
||||
@@ -159,32 +167,38 @@ func TestHandshakeBasic(t *testing.T) {
|
||||
// write more.
|
||||
<-checker.called
|
||||
}
|
||||
if (i % 10) == 7 {
|
||||
// write some packets until the kex
|
||||
// completes, to test buffering of
|
||||
// packets.
|
||||
checker.waitCall <- 1
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Server checks that client messages come in cleanly
|
||||
i := 0
|
||||
err = nil
|
||||
for ; i < 10; i++ {
|
||||
for ; i < N; i++ {
|
||||
var p []byte
|
||||
p, err = trS.readPacket()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if i == 5 {
|
||||
if (i % 10) == 5 {
|
||||
gotHalf <- 1
|
||||
}
|
||||
|
||||
want := []byte{msgRequestSuccess, byte(i)}
|
||||
if bytes.Compare(p, want) != 0 {
|
||||
t.Errorf("message %d: got %q, want %q", i, p, want)
|
||||
t.Errorf("message %d: got %v, want %v", i, p, want)
|
||||
}
|
||||
}
|
||||
<-clientDone
|
||||
if err != nil && err != io.EOF {
|
||||
t.Fatalf("server error: %v", err)
|
||||
}
|
||||
if i != 10 {
|
||||
if i != N {
|
||||
t.Errorf("received %d messages, want 10.", i)
|
||||
}
|
||||
|
||||
@@ -239,7 +253,10 @@ func TestForceFirstKex(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandshakeAutoRekeyWrite(t *testing.T) {
|
||||
checker := &syncChecker{make(chan int, 10)}
|
||||
checker := &syncChecker{
|
||||
called: make(chan int, 10),
|
||||
waitCall: nil,
|
||||
}
|
||||
clientConf := &ClientConfig{HostKeyCallback: checker.Check}
|
||||
clientConf.RekeyThreshold = 500
|
||||
trC, trS, err := handshakePair(clientConf, "addr", false)
|
||||
@@ -249,14 +266,19 @@ func TestHandshakeAutoRekeyWrite(t *testing.T) {
|
||||
defer trC.Close()
|
||||
defer trS.Close()
|
||||
|
||||
input := make([]byte, 251)
|
||||
input[0] = msgRequestSuccess
|
||||
|
||||
done := make(chan int, 1)
|
||||
const numPacket = 5
|
||||
go func() {
|
||||
defer close(done)
|
||||
j := 0
|
||||
for ; j < numPacket; j++ {
|
||||
if _, err := trS.readPacket(); err != nil {
|
||||
if p, err := trS.readPacket(); err != nil {
|
||||
break
|
||||
} else if !bytes.Equal(input, p) {
|
||||
t.Errorf("got packet type %d, want %d", p[0], input[0])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,9 +290,9 @@ func TestHandshakeAutoRekeyWrite(t *testing.T) {
|
||||
<-checker.called
|
||||
|
||||
for i := 0; i < numPacket; i++ {
|
||||
packet := make([]byte, 251)
|
||||
packet[0] = msgRequestSuccess
|
||||
if err := trC.writePacket(packet); err != nil {
|
||||
p := make([]byte, len(input))
|
||||
copy(p, input)
|
||||
if err := trC.writePacket(p); err != nil {
|
||||
t.Errorf("writePacket: %v", err)
|
||||
}
|
||||
if i == 2 {
|
||||
@@ -283,16 +305,23 @@ func TestHandshakeAutoRekeyWrite(t *testing.T) {
|
||||
}
|
||||
|
||||
type syncChecker struct {
|
||||
called chan int
|
||||
waitCall chan int
|
||||
called chan int
|
||||
}
|
||||
|
||||
func (c *syncChecker) Check(dialAddr string, addr net.Addr, key PublicKey) error {
|
||||
c.called <- 1
|
||||
if c.waitCall != nil {
|
||||
<-c.waitCall
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestHandshakeAutoRekeyRead(t *testing.T) {
|
||||
sync := &syncChecker{make(chan int, 2)}
|
||||
sync := &syncChecker{
|
||||
called: make(chan int, 2),
|
||||
waitCall: nil,
|
||||
}
|
||||
clientConf := &ClientConfig{
|
||||
HostKeyCallback: sync.Check,
|
||||
}
|
||||
|
||||
10
vendor/golang.org/x/crypto/ssh/mac.go
сгенерированный
поставляемый
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
type macMode struct {
|
||||
keySize int
|
||||
etm bool
|
||||
new func(key []byte) hash.Hash
|
||||
}
|
||||
|
||||
@@ -45,13 +46,16 @@ func (t truncatingMAC) Size() int {
|
||||
func (t truncatingMAC) BlockSize() int { return t.hmac.BlockSize() }
|
||||
|
||||
var macModes = map[string]*macMode{
|
||||
"hmac-sha2-256": {32, func(key []byte) hash.Hash {
|
||||
"hmac-sha2-256-etm@openssh.com": {32, true, func(key []byte) hash.Hash {
|
||||
return hmac.New(sha256.New, key)
|
||||
}},
|
||||
"hmac-sha1": {20, func(key []byte) hash.Hash {
|
||||
"hmac-sha2-256": {32, false, func(key []byte) hash.Hash {
|
||||
return hmac.New(sha256.New, key)
|
||||
}},
|
||||
"hmac-sha1": {20, false, func(key []byte) hash.Hash {
|
||||
return hmac.New(sha1.New, key)
|
||||
}},
|
||||
"hmac-sha1-96": {20, func(key []byte) hash.Hash {
|
||||
"hmac-sha1-96": {20, false, func(key []byte) hash.Hash {
|
||||
return truncatingMAC{12, hmac.New(sha1.New, key)}
|
||||
}},
|
||||
}
|
||||
|
||||
3
vendor/golang.org/x/crypto/ssh/mux_test.go
сгенерированный
поставляемый
@@ -499,4 +499,7 @@ func TestDebug(t *testing.T) {
|
||||
if debugHandshake {
|
||||
t.Error("handshake debug switched on")
|
||||
}
|
||||
if debugTransport {
|
||||
t.Error("transport debug switched on")
|
||||
}
|
||||
}
|
||||
|
||||
27
vendor/golang.org/x/crypto/ssh/server.go
сгенерированный
поставляемый
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// The Permissions type holds fine-grained permissions that are
|
||||
@@ -231,7 +232,7 @@ func isAcceptableAlgo(algo string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func checkSourceAddress(addr net.Addr, sourceAddr string) error {
|
||||
func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
|
||||
if addr == nil {
|
||||
return errors.New("ssh: no address known for client, but source-address match required")
|
||||
}
|
||||
@@ -241,18 +242,20 @@ func checkSourceAddress(addr net.Addr, sourceAddr string) error {
|
||||
return fmt.Errorf("ssh: remote address %v is not an TCP address when checking source-address match", addr)
|
||||
}
|
||||
|
||||
if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
|
||||
if allowedIP.Equal(tcpAddr.IP) {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
_, ipNet, err := net.ParseCIDR(sourceAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
|
||||
}
|
||||
for _, sourceAddr := range strings.Split(sourceAddrs, ",") {
|
||||
if allowedIP := net.ParseIP(sourceAddr); allowedIP != nil {
|
||||
if allowedIP.Equal(tcpAddr.IP) {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
_, ipNet, err := net.ParseCIDR(sourceAddr)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ssh: error parsing source-address restriction %q: %v", sourceAddr, err)
|
||||
}
|
||||
|
||||
if ipNet.Contains(tcpAddr.IP) {
|
||||
return nil
|
||||
if ipNet.Contains(tcpAddr.IP) {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
32
vendor/golang.org/x/crypto/ssh/transport.go
сгенерированный
поставляемый
@@ -8,8 +8,13 @@ import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"io"
|
||||
"log"
|
||||
)
|
||||
|
||||
// debugTransport if set, will print packet types as they go over the
|
||||
// wire. No message decoding is done, to minimize the impact on timing.
|
||||
const debugTransport = false
|
||||
|
||||
const (
|
||||
gcmCipherID = "aes128-gcm@openssh.com"
|
||||
aes128cbcID = "aes128-cbc"
|
||||
@@ -40,7 +45,7 @@ type transport struct {
|
||||
bufReader *bufio.Reader
|
||||
bufWriter *bufio.Writer
|
||||
rand io.Reader
|
||||
|
||||
isClient bool
|
||||
io.Closer
|
||||
}
|
||||
|
||||
@@ -86,6 +91,22 @@ func (t *transport) prepareKeyChange(algs *algorithms, kexResult *kexResult) err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *transport) printPacket(p []byte, write bool) {
|
||||
if len(p) == 0 {
|
||||
return
|
||||
}
|
||||
who := "server"
|
||||
if t.isClient {
|
||||
who = "client"
|
||||
}
|
||||
what := "read"
|
||||
if write {
|
||||
what = "write"
|
||||
}
|
||||
|
||||
log.Println(what, who, p[0])
|
||||
}
|
||||
|
||||
// Read and decrypt next packet.
|
||||
func (t *transport) readPacket() (p []byte, err error) {
|
||||
for {
|
||||
@@ -97,6 +118,9 @@ func (t *transport) readPacket() (p []byte, err error) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if debugTransport {
|
||||
t.printPacket(p, false)
|
||||
}
|
||||
|
||||
return p, err
|
||||
}
|
||||
@@ -141,6 +165,9 @@ func (s *connectionState) readPacket(r *bufio.Reader) ([]byte, error) {
|
||||
}
|
||||
|
||||
func (t *transport) writePacket(packet []byte) error {
|
||||
if debugTransport {
|
||||
t.printPacket(packet, true)
|
||||
}
|
||||
return t.writer.writePacket(t.bufWriter, t.rand, packet)
|
||||
}
|
||||
|
||||
@@ -181,6 +208,8 @@ func newTransport(rwc io.ReadWriteCloser, rand io.Reader, isClient bool) *transp
|
||||
},
|
||||
Closer: rwc,
|
||||
}
|
||||
t.isClient = isClient
|
||||
|
||||
if isClient {
|
||||
t.reader.dir = serverKeys
|
||||
t.writer.dir = clientKeys
|
||||
@@ -238,6 +267,7 @@ func newPacketCipher(d direction, algs directionAlgorithms, kex *kexResult) (pac
|
||||
|
||||
c := &streamPacketCipher{
|
||||
mac: macModes[algs.MAC].new(macKey),
|
||||
etm: macModes[algs.MAC].etm,
|
||||
}
|
||||
c.macResult = make([]byte, c.mac.Size())
|
||||
|
||||
|
||||
42
vendor/golang.org/x/image/draw/draw.go
сгенерированный
поставляемый
@@ -11,12 +11,12 @@
|
||||
// package in the standard library.
|
||||
package draw
|
||||
|
||||
// This file just contains the API exported by the image/draw package in the
|
||||
// standard library. Other files in this package provide additional features.
|
||||
// This file, and the go1_*.go files, just contains the API exported by the
|
||||
// image/draw package in the standard library. Other files in this package
|
||||
// provide additional features.
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
@@ -32,13 +32,6 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
|
||||
draw.DrawMask(dst, r, src, sp, mask, mp, draw.Op(op))
|
||||
}
|
||||
|
||||
// Drawer contains the Draw method.
|
||||
type Drawer interface {
|
||||
// Draw aligns r.Min in dst with sp in src and then replaces the
|
||||
// rectangle r in dst with the result of drawing src on dst.
|
||||
Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point)
|
||||
}
|
||||
|
||||
// FloydSteinberg is a Drawer that is the Src Op with Floyd-Steinberg error
|
||||
// diffusion.
|
||||
var FloydSteinberg Drawer = floydSteinberg{}
|
||||
@@ -48,32 +41,3 @@ type floydSteinberg struct{}
|
||||
func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||
draw.FloydSteinberg.Draw(dst, r, src, sp)
|
||||
}
|
||||
|
||||
// Image is an image.Image with a Set method to change a single pixel.
|
||||
type Image interface {
|
||||
image.Image
|
||||
Set(x, y int, c color.Color)
|
||||
}
|
||||
|
||||
// Op is a Porter-Duff compositing operator.
|
||||
type Op int
|
||||
|
||||
const (
|
||||
// Over specifies ``(src in mask) over dst''.
|
||||
Over Op = Op(draw.Over)
|
||||
// Src specifies ``src in mask''.
|
||||
Src Op = Op(draw.Src)
|
||||
)
|
||||
|
||||
// Draw implements the Drawer interface by calling the Draw function with
|
||||
// this Op.
|
||||
func (op Op) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||
(draw.Op(op)).Draw(dst, r, src, sp)
|
||||
}
|
||||
|
||||
// Quantizer produces a palette for an image.
|
||||
type Quantizer interface {
|
||||
// Quantize appends up to cap(p) - len(p) colors to p and returns the
|
||||
// updated palette suitable for converting m to a paletted image.
|
||||
Quantize(p color.Palette, m image.Image) color.Palette
|
||||
}
|
||||
|
||||
2
vendor/golang.org/x/image/draw/gen.go
сгенерированный
поставляемый
@@ -804,7 +804,7 @@ func cOffset(x, y, sratio string) string {
|
||||
func ycbcrToRGB(lhs, tmp string) string {
|
||||
s := `
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
$yy1 := int(src.Y[$i]) * 0x10100
|
||||
$yy1 := int(src.Y[$i]) * 0x10101
|
||||
$cb1 := int(src.Cb[$j]) - 128
|
||||
$cr1 := int(src.Cr[$j]) - 128
|
||||
$r@ := ($yy1 + 91881*$cr1) >> 8
|
||||
|
||||
49
vendor/golang.org/x/image/draw/go1_8.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,49 @@
|
||||
// Copyright 2015 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.
|
||||
|
||||
// +build !go1.9,!go1.8.typealias
|
||||
|
||||
package draw
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
// Drawer contains the Draw method.
|
||||
type Drawer interface {
|
||||
// Draw aligns r.Min in dst with sp in src and then replaces the
|
||||
// rectangle r in dst with the result of drawing src on dst.
|
||||
Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point)
|
||||
}
|
||||
|
||||
// Image is an image.Image with a Set method to change a single pixel.
|
||||
type Image interface {
|
||||
image.Image
|
||||
Set(x, y int, c color.Color)
|
||||
}
|
||||
|
||||
// Op is a Porter-Duff compositing operator.
|
||||
type Op int
|
||||
|
||||
const (
|
||||
// Over specifies ``(src in mask) over dst''.
|
||||
Over Op = Op(draw.Over)
|
||||
// Src specifies ``src in mask''.
|
||||
Src Op = Op(draw.Src)
|
||||
)
|
||||
|
||||
// Draw implements the Drawer interface by calling the Draw function with
|
||||
// this Op.
|
||||
func (op Op) Draw(dst Image, r image.Rectangle, src image.Image, sp image.Point) {
|
||||
(draw.Op(op)).Draw(dst, r, src, sp)
|
||||
}
|
||||
|
||||
// Quantizer produces a palette for an image.
|
||||
type Quantizer interface {
|
||||
// Quantize appends up to cap(p) - len(p) colors to p and returns the
|
||||
// updated palette suitable for converting m to a paletted image.
|
||||
Quantize(p color.Palette, m image.Image) color.Palette
|
||||
}
|
||||
57
vendor/golang.org/x/image/draw/go1_9.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,57 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
// +build go1.9 go1.8.typealias
|
||||
|
||||
package draw
|
||||
|
||||
import (
|
||||
"image/draw"
|
||||
)
|
||||
|
||||
// We use type aliases (new in Go 1.9) for the exported names from the standard
|
||||
// library's image/draw package. This is not merely syntactic sugar for
|
||||
//
|
||||
// type Drawer draw.Drawer
|
||||
//
|
||||
// as aliasing means that the types in this package, such as draw.Image and
|
||||
// draw.Op, are identical to the corresponding draw.Image and draw.Op types in
|
||||
// the standard library. In comparison, prior to Go 1.9, the code in go1_8.go
|
||||
// defines new types that mimic the old but are different types.
|
||||
//
|
||||
// The package documentation, in draw.go, explicitly gives the intent of this
|
||||
// package:
|
||||
//
|
||||
// This package is a superset of and a drop-in replacement for the
|
||||
// image/draw package in the standard library.
|
||||
//
|
||||
// Drop-in replacement means that I can replace all of my "image/draw" imports
|
||||
// with "golang.org/x/image/draw", to access additional features in this
|
||||
// package, and no further changes are required. That's mostly true, but not
|
||||
// completely true unless we use type aliases.
|
||||
//
|
||||
// Without type aliases, users might need to import both "image/draw" and
|
||||
// "golang.org/x/image/draw" in order to convert from two conceptually
|
||||
// equivalent but different (from the compiler's point of view) types, such as
|
||||
// from one draw.Op type to another draw.Op type, to satisfy some other
|
||||
// interface or function signature.
|
||||
|
||||
// Drawer contains the Draw method.
|
||||
type Drawer = draw.Drawer
|
||||
|
||||
// Image is an image.Image with a Set method to change a single pixel.
|
||||
type Image = draw.Image
|
||||
|
||||
// Op is a Porter-Duff compositing operator.
|
||||
type Op = draw.Op
|
||||
|
||||
const (
|
||||
// Over specifies ``(src in mask) over dst''.
|
||||
Over Op = draw.Over
|
||||
// Src specifies ``src in mask''.
|
||||
Src Op = draw.Src
|
||||
)
|
||||
|
||||
// Quantizer produces a palette for an image.
|
||||
type Quantizer = draw.Quantizer
|
||||
96
vendor/golang.org/x/image/draw/impl.go
сгенерированный
поставляемый
@@ -343,7 +343,7 @@ func (nnInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rec
|
||||
pj := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pr := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -386,7 +386,7 @@ func (nnInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rec
|
||||
pj := (sr.Min.Y+int(sy)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pr := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -429,7 +429,7 @@ func (nnInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rec
|
||||
pj := ((sr.Min.Y+int(sy))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pr := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -472,7 +472,7 @@ func (nnInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rec
|
||||
pj := ((sr.Min.Y+int(sy))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pr := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -759,7 +759,7 @@ func (nnInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image
|
||||
pj := (sy0-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pr := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -803,7 +803,7 @@ func (nnInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image
|
||||
pj := (sy0-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pr := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -847,7 +847,7 @@ func (nnInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image
|
||||
pj := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pr := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -891,7 +891,7 @@ func (nnInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image
|
||||
pj := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pr := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -1756,7 +1756,7 @@ func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s00j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10100
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10101
|
||||
s00cb1 := int(src.Cb[s00j]) - 128
|
||||
s00cr1 := int(src.Cr[s00j]) - 128
|
||||
s00ru := (s00yy1 + 91881*s00cr1) >> 8
|
||||
@@ -1785,7 +1785,7 @@ func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s10j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10100
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10101
|
||||
s10cb1 := int(src.Cb[s10j]) - 128
|
||||
s10cr1 := int(src.Cr[s10j]) - 128
|
||||
s10ru := (s10yy1 + 91881*s10cr1) >> 8
|
||||
@@ -1817,7 +1817,7 @@ func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10100
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10101
|
||||
s01cb1 := int(src.Cb[s01j]) - 128
|
||||
s01cr1 := int(src.Cr[s01j]) - 128
|
||||
s01ru := (s01yy1 + 91881*s01cr1) >> 8
|
||||
@@ -1846,7 +1846,7 @@ func (ablInterpolator) scale_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s11j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10100
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10101
|
||||
s11cb1 := int(src.Cb[s11j]) - 128
|
||||
s11cr1 := int(src.Cr[s11j]) - 128
|
||||
s11ru := (s11yy1 + 91881*s11cr1) >> 8
|
||||
@@ -1931,7 +1931,7 @@ func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s00j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10100
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10101
|
||||
s00cb1 := int(src.Cb[s00j]) - 128
|
||||
s00cr1 := int(src.Cr[s00j]) - 128
|
||||
s00ru := (s00yy1 + 91881*s00cr1) >> 8
|
||||
@@ -1960,7 +1960,7 @@ func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s10j := (sr.Min.Y+int(sy0)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10100
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10101
|
||||
s10cb1 := int(src.Cb[s10j]) - 128
|
||||
s10cr1 := int(src.Cr[s10j]) - 128
|
||||
s10ru := (s10yy1 + 91881*s10cr1) >> 8
|
||||
@@ -1992,7 +1992,7 @@ func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s01j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10100
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10101
|
||||
s01cb1 := int(src.Cb[s01j]) - 128
|
||||
s01cr1 := int(src.Cr[s01j]) - 128
|
||||
s01ru := (s01yy1 + 91881*s01cr1) >> 8
|
||||
@@ -2021,7 +2021,7 @@ func (ablInterpolator) scale_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s11j := (sr.Min.Y+int(sy1)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10100
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10101
|
||||
s11cb1 := int(src.Cb[s11j]) - 128
|
||||
s11cr1 := int(src.Cr[s11j]) - 128
|
||||
s11ru := (s11yy1 + 91881*s11cr1) >> 8
|
||||
@@ -2106,7 +2106,7 @@ func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s00j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10100
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10101
|
||||
s00cb1 := int(src.Cb[s00j]) - 128
|
||||
s00cr1 := int(src.Cr[s00j]) - 128
|
||||
s00ru := (s00yy1 + 91881*s00cr1) >> 8
|
||||
@@ -2135,7 +2135,7 @@ func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s10j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10100
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10101
|
||||
s10cb1 := int(src.Cb[s10j]) - 128
|
||||
s10cr1 := int(src.Cr[s10j]) - 128
|
||||
s10ru := (s10yy1 + 91881*s10cr1) >> 8
|
||||
@@ -2167,7 +2167,7 @@ func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx0))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10100
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10101
|
||||
s01cb1 := int(src.Cb[s01j]) - 128
|
||||
s01cr1 := int(src.Cr[s01j]) - 128
|
||||
s01ru := (s01yy1 + 91881*s01cr1) >> 8
|
||||
@@ -2196,7 +2196,7 @@ func (ablInterpolator) scale_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s11j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(sx1))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10100
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10101
|
||||
s11cb1 := int(src.Cb[s11j]) - 128
|
||||
s11cr1 := int(src.Cr[s11j]) - 128
|
||||
s11ru := (s11yy1 + 91881*s11cr1) >> 8
|
||||
@@ -2281,7 +2281,7 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s00j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10100
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10101
|
||||
s00cb1 := int(src.Cb[s00j]) - 128
|
||||
s00cr1 := int(src.Cr[s00j]) - 128
|
||||
s00ru := (s00yy1 + 91881*s00cr1) >> 8
|
||||
@@ -2310,7 +2310,7 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s10j := ((sr.Min.Y+int(sy0))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10100
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10101
|
||||
s10cb1 := int(src.Cb[s10j]) - 128
|
||||
s10cr1 := int(src.Cr[s10j]) - 128
|
||||
s10ru := (s10yy1 + 91881*s10cr1) >> 8
|
||||
@@ -2342,7 +2342,7 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s01j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx0) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10100
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10101
|
||||
s01cb1 := int(src.Cb[s01j]) - 128
|
||||
s01cr1 := int(src.Cr[s01j]) - 128
|
||||
s01ru := (s01yy1 + 91881*s01cr1) >> 8
|
||||
@@ -2371,7 +2371,7 @@ func (ablInterpolator) scale_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Re
|
||||
s11j := ((sr.Min.Y+int(sy1))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(sx1) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10100
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10101
|
||||
s11cb1 := int(src.Cb[s11j]) - 128
|
||||
s11cr1 := int(src.Cr[s11j]) - 128
|
||||
s11ru := (s11yy1 + 91881*s11cr1) >> 8
|
||||
@@ -3345,7 +3345,7 @@ func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr imag
|
||||
s00j := (sy0-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10100
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10101
|
||||
s00cb1 := int(src.Cb[s00j]) - 128
|
||||
s00cr1 := int(src.Cr[s00j]) - 128
|
||||
s00ru := (s00yy1 + 91881*s00cr1) >> 8
|
||||
@@ -3374,7 +3374,7 @@ func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr imag
|
||||
s10j := (sy0-src.Rect.Min.Y)*src.CStride + (sx1 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10100
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10101
|
||||
s10cb1 := int(src.Cb[s10j]) - 128
|
||||
s10cr1 := int(src.Cr[s10j]) - 128
|
||||
s10ru := (s10yy1 + 91881*s10cr1) >> 8
|
||||
@@ -3406,7 +3406,7 @@ func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr imag
|
||||
s01j := (sy1-src.Rect.Min.Y)*src.CStride + (sx0 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10100
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10101
|
||||
s01cb1 := int(src.Cb[s01j]) - 128
|
||||
s01cr1 := int(src.Cr[s01j]) - 128
|
||||
s01ru := (s01yy1 + 91881*s01cr1) >> 8
|
||||
@@ -3435,7 +3435,7 @@ func (ablInterpolator) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr imag
|
||||
s11j := (sy1-src.Rect.Min.Y)*src.CStride + (sx1 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10100
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10101
|
||||
s11cb1 := int(src.Cb[s11j]) - 128
|
||||
s11cr1 := int(src.Cr[s11j]) - 128
|
||||
s11ru := (s11yy1 + 91881*s11cr1) >> 8
|
||||
@@ -3521,7 +3521,7 @@ func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr imag
|
||||
s00j := (sy0-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10100
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10101
|
||||
s00cb1 := int(src.Cb[s00j]) - 128
|
||||
s00cr1 := int(src.Cr[s00j]) - 128
|
||||
s00ru := (s00yy1 + 91881*s00cr1) >> 8
|
||||
@@ -3550,7 +3550,7 @@ func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr imag
|
||||
s10j := (sy0-src.Rect.Min.Y)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10100
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10101
|
||||
s10cb1 := int(src.Cb[s10j]) - 128
|
||||
s10cr1 := int(src.Cr[s10j]) - 128
|
||||
s10ru := (s10yy1 + 91881*s10cr1) >> 8
|
||||
@@ -3582,7 +3582,7 @@ func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr imag
|
||||
s01j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10100
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10101
|
||||
s01cb1 := int(src.Cb[s01j]) - 128
|
||||
s01cr1 := int(src.Cr[s01j]) - 128
|
||||
s01ru := (s01yy1 + 91881*s01cr1) >> 8
|
||||
@@ -3611,7 +3611,7 @@ func (ablInterpolator) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr imag
|
||||
s11j := (sy1-src.Rect.Min.Y)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10100
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10101
|
||||
s11cb1 := int(src.Cb[s11j]) - 128
|
||||
s11cr1 := int(src.Cr[s11j]) - 128
|
||||
s11ru := (s11yy1 + 91881*s11cr1) >> 8
|
||||
@@ -3697,7 +3697,7 @@ func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr imag
|
||||
s00j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10100
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10101
|
||||
s00cb1 := int(src.Cb[s00j]) - 128
|
||||
s00cr1 := int(src.Cr[s00j]) - 128
|
||||
s00ru := (s00yy1 + 91881*s00cr1) >> 8
|
||||
@@ -3726,7 +3726,7 @@ func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr imag
|
||||
s10j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10100
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10101
|
||||
s10cb1 := int(src.Cb[s10j]) - 128
|
||||
s10cr1 := int(src.Cr[s10j]) - 128
|
||||
s10ru := (s10yy1 + 91881*s10cr1) >> 8
|
||||
@@ -3758,7 +3758,7 @@ func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr imag
|
||||
s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx0)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10100
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10101
|
||||
s01cb1 := int(src.Cb[s01j]) - 128
|
||||
s01cr1 := int(src.Cr[s01j]) - 128
|
||||
s01ru := (s01yy1 + 91881*s01cr1) >> 8
|
||||
@@ -3787,7 +3787,7 @@ func (ablInterpolator) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr imag
|
||||
s11j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + ((sx1)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10100
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10101
|
||||
s11cb1 := int(src.Cb[s11j]) - 128
|
||||
s11cr1 := int(src.Cr[s11j]) - 128
|
||||
s11ru := (s11yy1 + 91881*s11cr1) >> 8
|
||||
@@ -3873,7 +3873,7 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag
|
||||
s00j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10100
|
||||
s00yy1 := int(src.Y[s00i]) * 0x10101
|
||||
s00cb1 := int(src.Cb[s00j]) - 128
|
||||
s00cr1 := int(src.Cr[s00j]) - 128
|
||||
s00ru := (s00yy1 + 91881*s00cr1) >> 8
|
||||
@@ -3902,7 +3902,7 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag
|
||||
s10j := ((sy0)/2-src.Rect.Min.Y/2)*src.CStride + (sx1 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10100
|
||||
s10yy1 := int(src.Y[s10i]) * 0x10101
|
||||
s10cb1 := int(src.Cb[s10j]) - 128
|
||||
s10cr1 := int(src.Cr[s10j]) - 128
|
||||
s10ru := (s10yy1 + 91881*s10cr1) >> 8
|
||||
@@ -3934,7 +3934,7 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag
|
||||
s01j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx0 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10100
|
||||
s01yy1 := int(src.Y[s01i]) * 0x10101
|
||||
s01cb1 := int(src.Cb[s01j]) - 128
|
||||
s01cr1 := int(src.Cr[s01j]) - 128
|
||||
s01ru := (s01yy1 + 91881*s01cr1) >> 8
|
||||
@@ -3963,7 +3963,7 @@ func (ablInterpolator) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr imag
|
||||
s11j := ((sy1)/2-src.Rect.Min.Y/2)*src.CStride + (sx1 - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10100
|
||||
s11yy1 := int(src.Y[s11i]) * 0x10101
|
||||
s11cb1 := int(src.Cb[s11j]) - 128
|
||||
s11cr1 := int(src.Cr[s11j]) - 128
|
||||
s11ru := (s11yy1 + 91881*s11cr1) >> 8
|
||||
@@ -4729,7 +4729,7 @@ func (z *kernelScaler) scaleX_YCbCr444(tmp [][4]float64, src *image.YCbCr, sr im
|
||||
pj := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.CStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pru := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -4776,7 +4776,7 @@ func (z *kernelScaler) scaleX_YCbCr422(tmp [][4]float64, src *image.YCbCr, sr im
|
||||
pj := (sr.Min.Y+int(y)-src.Rect.Min.Y)*src.CStride + ((sr.Min.X+int(c.coord))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pru := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -4823,7 +4823,7 @@ func (z *kernelScaler) scaleX_YCbCr420(tmp [][4]float64, src *image.YCbCr, sr im
|
||||
pj := ((sr.Min.Y+int(y))/2-src.Rect.Min.Y/2)*src.CStride + ((sr.Min.X+int(c.coord))/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pru := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -4870,7 +4870,7 @@ func (z *kernelScaler) scaleX_YCbCr440(tmp [][4]float64, src *image.YCbCr, sr im
|
||||
pj := ((sr.Min.Y+int(y))/2-src.Rect.Min.Y/2)*src.CStride + (sr.Min.X + int(c.coord) - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pru := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -5759,7 +5759,7 @@ func (q *Kernel) transform_RGBA_YCbCr444_Src(dst *image.RGBA, dr, adr image.Rect
|
||||
pj := (ky-src.Rect.Min.Y)*src.CStride + (kx - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pru := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -5883,7 +5883,7 @@ func (q *Kernel) transform_RGBA_YCbCr422_Src(dst *image.RGBA, dr, adr image.Rect
|
||||
pj := (ky-src.Rect.Min.Y)*src.CStride + ((kx)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pru := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -6007,7 +6007,7 @@ func (q *Kernel) transform_RGBA_YCbCr420_Src(dst *image.RGBA, dr, adr image.Rect
|
||||
pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + ((kx)/2 - src.Rect.Min.X/2)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pru := (pyy1 + 91881*pcr1) >> 8
|
||||
@@ -6131,7 +6131,7 @@ func (q *Kernel) transform_RGBA_YCbCr440_Src(dst *image.RGBA, dr, adr image.Rect
|
||||
pj := ((ky)/2-src.Rect.Min.Y/2)*src.CStride + (kx - src.Rect.Min.X)
|
||||
|
||||
// This is an inline version of image/color/ycbcr.go's YCbCr.RGBA method.
|
||||
pyy1 := int(src.Y[pi]) * 0x10100
|
||||
pyy1 := int(src.Y[pi]) * 0x10101
|
||||
pcb1 := int(src.Cb[pj]) - 128
|
||||
pcr1 := int(src.Cr[pj]) - 128
|
||||
pru := (pyy1 + 91881*pcr1) >> 8
|
||||
|
||||
6
vendor/golang.org/x/image/draw/stdlib_test.go
сгенерированный
поставляемый
@@ -2,14 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build go1.5
|
||||
// +build go1.9
|
||||
|
||||
package draw
|
||||
|
||||
// This file contains tests that depend on the exact behavior of the
|
||||
// image/color package in the standard library. The color conversion formula
|
||||
// from YCbCr to RGBA changed between Go 1.4 and Go 1.5, so this file's tests
|
||||
// are only enabled for Go 1.5 and above.
|
||||
// from YCbCr to RGBA changed between Go 1.4 and Go 1.5, and between Go 1.8 and
|
||||
// Go 1.9, so this file's tests are only enabled for Go 1.9 and above.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
269
vendor/golang.org/x/image/font/sfnt/cmap.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,269 @@
|
||||
// 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 sfnt
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"golang.org/x/text/encoding/charmap"
|
||||
)
|
||||
|
||||
// Platform IDs and Platform Specific IDs as per
|
||||
// https://www.microsoft.com/typography/otspec/name.htm
|
||||
const (
|
||||
pidUnicode = 0
|
||||
pidMacintosh = 1
|
||||
pidWindows = 3
|
||||
|
||||
psidUnicode2BMPOnly = 3
|
||||
psidUnicode2FullRepertoire = 4
|
||||
// Note that FontForge may generate a bogus Platform Specific ID (value 10)
|
||||
// for the Unicode Platform ID (value 0). See
|
||||
// https://github.com/fontforge/fontforge/issues/2728
|
||||
|
||||
psidMacintoshRoman = 0
|
||||
|
||||
psidWindowsSymbol = 0
|
||||
psidWindowsUCS2 = 1
|
||||
psidWindowsUCS4 = 10
|
||||
)
|
||||
|
||||
// platformEncodingWidth returns the number of bytes per character assumed by
|
||||
// the given Platform ID and Platform Specific ID.
|
||||
//
|
||||
// Very old fonts, from before Unicode was widely adopted, assume only 1 byte
|
||||
// per character: a character map.
|
||||
//
|
||||
// Old fonts, from when Unicode meant the Basic Multilingual Plane (BMP),
|
||||
// assume that 2 bytes per character is sufficient.
|
||||
//
|
||||
// Recent fonts naturally support the full range of Unicode code points, which
|
||||
// can take up to 4 bytes per character. Such fonts might still choose one of
|
||||
// the legacy encodings if e.g. their repertoire is limited to the BMP, for
|
||||
// greater compatibility with older software, or because the resultant file
|
||||
// size can be smaller.
|
||||
func platformEncodingWidth(pid, psid uint16) int {
|
||||
switch pid {
|
||||
case pidUnicode:
|
||||
switch psid {
|
||||
case psidUnicode2BMPOnly:
|
||||
return 2
|
||||
case psidUnicode2FullRepertoire:
|
||||
return 4
|
||||
}
|
||||
|
||||
case pidMacintosh:
|
||||
switch psid {
|
||||
case psidMacintoshRoman:
|
||||
return 1
|
||||
}
|
||||
|
||||
case pidWindows:
|
||||
switch psid {
|
||||
case psidWindowsSymbol:
|
||||
return 2
|
||||
case psidWindowsUCS2:
|
||||
return 2
|
||||
case psidWindowsUCS4:
|
||||
return 4
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// The various cmap formats are described at
|
||||
// https://www.microsoft.com/typography/otspec/cmap.htm
|
||||
|
||||
var supportedCmapFormat = func(format, pid, psid uint16) bool {
|
||||
switch format {
|
||||
case 0:
|
||||
return pid == pidMacintosh && psid == psidMacintoshRoman
|
||||
case 4:
|
||||
return true
|
||||
case 12:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndex(buf []byte, offset, length uint32, format uint16) ([]byte, glyphIndexFunc, error) {
|
||||
switch format {
|
||||
case 0:
|
||||
return f.makeCachedGlyphIndexFormat0(buf, offset, length)
|
||||
case 4:
|
||||
return f.makeCachedGlyphIndexFormat4(buf, offset, length)
|
||||
case 12:
|
||||
return f.makeCachedGlyphIndexFormat12(buf, offset, length)
|
||||
}
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndexFormat0(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
|
||||
if length != 6+256 || offset+length > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
var err error
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(length))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var table [256]byte
|
||||
copy(table[:], buf[6:])
|
||||
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
|
||||
// TODO: for this closure to be goroutine-safe, the
|
||||
// golang.org/x/text/encoding/charmap API needs to allocate a new
|
||||
// Encoder and new []byte buffers, for every call to this closure, even
|
||||
// though all we want to do is to encode one rune as one byte. We could
|
||||
// possibly add some fields in the Buffer struct to re-use these
|
||||
// allocations, but a better solution is to improve the charmap API.
|
||||
var dst, src [utf8.UTFMax]byte
|
||||
n := utf8.EncodeRune(src[:], r)
|
||||
_, _, err = charmap.Macintosh.NewEncoder().Transform(dst[:], src[:n], true)
|
||||
if err != nil {
|
||||
// The source rune r is not representable in the Macintosh-Roman encoding.
|
||||
return 0, nil
|
||||
}
|
||||
return GlyphIndex(table[dst[0]]), nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndexFormat4(buf []byte, offset, length uint32) ([]byte, glyphIndexFunc, error) {
|
||||
const headerSize = 14
|
||||
if offset+headerSize > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
var err error
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
offset += headerSize
|
||||
|
||||
segCount := u16(buf[6:])
|
||||
if segCount&1 != 0 {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
segCount /= 2
|
||||
if segCount > maxCmapSegments {
|
||||
return nil, nil, errUnsupportedNumberOfCmapSegments
|
||||
}
|
||||
|
||||
eLength := 8*uint32(segCount) + 2
|
||||
if offset+eLength > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
offset += eLength
|
||||
|
||||
entries := make([]cmapEntry16, segCount)
|
||||
for i := range entries {
|
||||
entries[i] = cmapEntry16{
|
||||
end: u16(buf[0*len(entries)+0+2*i:]),
|
||||
start: u16(buf[2*len(entries)+2+2*i:]),
|
||||
delta: u16(buf[4*len(entries)+2+2*i:]),
|
||||
offset: u16(buf[6*len(entries)+2+2*i:]),
|
||||
}
|
||||
}
|
||||
indexesBase := f.cmap.offset + offset
|
||||
indexesLength := f.cmap.length - offset
|
||||
|
||||
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
|
||||
if uint32(r) > 0xffff {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
c := uint16(r)
|
||||
for i, j := 0, len(entries); i < j; {
|
||||
h := i + (j-i)/2
|
||||
entry := &entries[h]
|
||||
if c < entry.start {
|
||||
j = h
|
||||
} else if entry.end < c {
|
||||
i = h + 1
|
||||
} else if entry.offset == 0 {
|
||||
return GlyphIndex(c + entry.delta), nil
|
||||
} else {
|
||||
offset := uint32(entry.offset) + 2*uint32(h-len(entries)+int(c-entry.start))
|
||||
if offset > indexesLength || offset+2 > indexesLength {
|
||||
return 0, errInvalidCmapTable
|
||||
}
|
||||
x, err := b.view(&f.src, int(indexesBase+offset), 2)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return GlyphIndex(u16(x)), nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f *Font) makeCachedGlyphIndexFormat12(buf []byte, offset, _ uint32) ([]byte, glyphIndexFunc, error) {
|
||||
const headerSize = 16
|
||||
if offset+headerSize > f.cmap.length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
var err error
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), headerSize)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
length := u32(buf[4:])
|
||||
if f.cmap.length < offset || length > f.cmap.length-offset {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
offset += headerSize
|
||||
|
||||
numGroups := u32(buf[12:])
|
||||
if numGroups > maxCmapSegments {
|
||||
return nil, nil, errUnsupportedNumberOfCmapSegments
|
||||
}
|
||||
|
||||
eLength := 12 * numGroups
|
||||
if headerSize+eLength != length {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), int(eLength))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
offset += eLength
|
||||
|
||||
entries := make([]cmapEntry32, numGroups)
|
||||
for i := range entries {
|
||||
entries[i] = cmapEntry32{
|
||||
start: u32(buf[0+12*i:]),
|
||||
end: u32(buf[4+12*i:]),
|
||||
delta: u32(buf[8+12*i:]),
|
||||
}
|
||||
}
|
||||
|
||||
return buf, func(f *Font, b *Buffer, r rune) (GlyphIndex, error) {
|
||||
c := uint32(r)
|
||||
for i, j := 0, len(entries); i < j; {
|
||||
h := i + (j-i)/2
|
||||
entry := &entries[h]
|
||||
if c < entry.start {
|
||||
j = h
|
||||
} else if entry.end < c {
|
||||
i = h + 1
|
||||
} else {
|
||||
return GlyphIndex(c - entry.start + entry.delta), nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
type cmapEntry16 struct {
|
||||
end, start, delta, offset uint16
|
||||
}
|
||||
|
||||
type cmapEntry32 struct {
|
||||
start, end, delta uint32
|
||||
}
|
||||
68
vendor/golang.org/x/image/font/sfnt/data.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,68 @@
|
||||
// generated by go run gen.go; DO NOT EDIT
|
||||
|
||||
package sfnt
|
||||
|
||||
const numBuiltInPostNames = 258
|
||||
|
||||
const builtInPostNamesData = "" +
|
||||
".notdef.nullnonmarkingreturnspaceexclamquotedblnumbersigndollarp" +
|
||||
"ercentampersandquotesingleparenleftparenrightasteriskpluscommahy" +
|
||||
"phenperiodslashzeroonetwothreefourfivesixseveneightninecolonsemi" +
|
||||
"colonlessequalgreaterquestionatABCDEFGHIJKLMNOPQRSTUVWXYZbracket" +
|
||||
"leftbackslashbracketrightasciicircumunderscoregraveabcdefghijklm" +
|
||||
"nopqrstuvwxyzbraceleftbarbracerightasciitildeAdieresisAringCcedi" +
|
||||
"llaEacuteNtildeOdieresisUdieresisaacuteagraveacircumflexadieresi" +
|
||||
"satildearingccedillaeacuteegraveecircumflexedieresisiacuteigrave" +
|
||||
"icircumflexidieresisntildeoacuteograveocircumflexodieresisotilde" +
|
||||
"uacuteugraveucircumflexudieresisdaggerdegreecentsterlingsectionb" +
|
||||
"ulletparagraphgermandblsregisteredcopyrighttrademarkacutedieresi" +
|
||||
"snotequalAEOslashinfinityplusminuslessequalgreaterequalyenmupart" +
|
||||
"ialdiffsummationproductpiintegralordfeminineordmasculineOmegaaeo" +
|
||||
"slashquestiondownexclamdownlogicalnotradicalflorinapproxequalDel" +
|
||||
"taguillemotleftguillemotrightellipsisnonbreakingspaceAgraveAtild" +
|
||||
"eOtildeOEoeendashemdashquotedblleftquotedblrightquoteleftquoteri" +
|
||||
"ghtdividelozengeydieresisYdieresisfractioncurrencyguilsinglleftg" +
|
||||
"uilsinglrightfifldaggerdblperiodcenteredquotesinglbasequotedblba" +
|
||||
"seperthousandAcircumflexEcircumflexAacuteEdieresisEgraveIacuteIc" +
|
||||
"ircumflexIdieresisIgraveOacuteOcircumflexappleOgraveUacuteUcircu" +
|
||||
"mflexUgravedotlessicircumflextildemacronbrevedotaccentringcedill" +
|
||||
"ahungarumlautogonekcaronLslashlslashScaronscaronZcaronzcaronbrok" +
|
||||
"enbarEthethYacuteyacuteThornthornminusmultiplyonesuperiortwosupe" +
|
||||
"riorthreesuperioronehalfonequarterthreequartersfrancGbrevegbreve" +
|
||||
"IdotaccentScedillascedillaCacutecacuteCcaronccarondcroat"
|
||||
|
||||
var builtInPostNamesOffsets = [...]uint16{
|
||||
0x0000, 0x0007, 0x000c, 0x001c, 0x0021, 0x0027, 0x002f, 0x0039,
|
||||
0x003f, 0x0046, 0x004f, 0x005a, 0x0063, 0x006d, 0x0075, 0x0079,
|
||||
0x007e, 0x0084, 0x008a, 0x008f, 0x0093, 0x0096, 0x0099, 0x009e,
|
||||
0x00a2, 0x00a6, 0x00a9, 0x00ae, 0x00b3, 0x00b7, 0x00bc, 0x00c5,
|
||||
0x00c9, 0x00ce, 0x00d5, 0x00dd, 0x00df, 0x00e0, 0x00e1, 0x00e2,
|
||||
0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea,
|
||||
0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2,
|
||||
0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x0104,
|
||||
0x010d, 0x0119, 0x0124, 0x012e, 0x0133, 0x0134, 0x0135, 0x0136,
|
||||
0x0137, 0x0138, 0x0139, 0x013a, 0x013b, 0x013c, 0x013d, 0x013e,
|
||||
0x013f, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0145, 0x0146,
|
||||
0x0147, 0x0148, 0x0149, 0x014a, 0x014b, 0x014c, 0x014d, 0x0156,
|
||||
0x0159, 0x0163, 0x016d, 0x0176, 0x017b, 0x0183, 0x0189, 0x018f,
|
||||
0x0198, 0x01a1, 0x01a7, 0x01ad, 0x01b8, 0x01c1, 0x01c7, 0x01cc,
|
||||
0x01d4, 0x01da, 0x01e0, 0x01eb, 0x01f4, 0x01fa, 0x0200, 0x020b,
|
||||
0x0214, 0x021a, 0x0220, 0x0226, 0x0231, 0x023a, 0x0240, 0x0246,
|
||||
0x024c, 0x0257, 0x0260, 0x0266, 0x026c, 0x0270, 0x0278, 0x027f,
|
||||
0x0285, 0x028e, 0x0298, 0x02a2, 0x02ab, 0x02b4, 0x02b9, 0x02c1,
|
||||
0x02c9, 0x02cb, 0x02d1, 0x02d9, 0x02e2, 0x02eb, 0x02f7, 0x02fa,
|
||||
0x02fc, 0x0307, 0x0310, 0x0317, 0x0319, 0x0321, 0x032c, 0x0338,
|
||||
0x033d, 0x033f, 0x0345, 0x0351, 0x035b, 0x0365, 0x036c, 0x0372,
|
||||
0x037d, 0x0382, 0x038f, 0x039d, 0x03a5, 0x03b5, 0x03bb, 0x03c1,
|
||||
0x03c7, 0x03c9, 0x03cb, 0x03d1, 0x03d7, 0x03e3, 0x03f0, 0x03f9,
|
||||
0x0403, 0x0409, 0x0410, 0x0419, 0x0422, 0x042a, 0x0432, 0x043f,
|
||||
0x044d, 0x044f, 0x0451, 0x045a, 0x0468, 0x0476, 0x0482, 0x048d,
|
||||
0x0498, 0x04a3, 0x04a9, 0x04b2, 0x04b8, 0x04be, 0x04c9, 0x04d2,
|
||||
0x04d8, 0x04de, 0x04e9, 0x04ee, 0x04f4, 0x04fa, 0x0505, 0x050b,
|
||||
0x0513, 0x051d, 0x0522, 0x0528, 0x052d, 0x0536, 0x053a, 0x0541,
|
||||
0x054d, 0x0553, 0x0558, 0x055e, 0x0564, 0x056a, 0x0570, 0x0576,
|
||||
0x057c, 0x0585, 0x0588, 0x058b, 0x0591, 0x0597, 0x059c, 0x05a1,
|
||||
0x05a6, 0x05ae, 0x05b9, 0x05c4, 0x05d1, 0x05d8, 0x05e2, 0x05ef,
|
||||
0x05f4, 0x05fa, 0x0600, 0x060a, 0x0612, 0x061a, 0x0620, 0x0626,
|
||||
0x062c, 0x0632, 0x0638,
|
||||
}
|
||||
128
vendor/golang.org/x/image/font/sfnt/example_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,128 @@
|
||||
// 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 sfnt_test
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/draw"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"golang.org/x/image/font/gofont/goregular"
|
||||
"golang.org/x/image/font/sfnt"
|
||||
"golang.org/x/image/math/fixed"
|
||||
"golang.org/x/image/vector"
|
||||
)
|
||||
|
||||
func ExampleRasterizeGlyph() {
|
||||
const (
|
||||
ppem = 32
|
||||
width = 24
|
||||
height = 32
|
||||
originX = 0
|
||||
originY = 28
|
||||
)
|
||||
|
||||
f, err := sfnt.Parse(goregular.TTF)
|
||||
if err != nil {
|
||||
log.Fatalf("Parse: %v", err)
|
||||
}
|
||||
var b sfnt.Buffer
|
||||
x, err := f.GlyphIndex(&b, 'G')
|
||||
if err != nil {
|
||||
log.Fatalf("GlyphIndex: %v", err)
|
||||
}
|
||||
if x == 0 {
|
||||
log.Fatalf("GlyphIndex: no glyph index found for the rune 'G'")
|
||||
}
|
||||
segments, err := f.LoadGlyph(&b, x, fixed.I(ppem), nil)
|
||||
if err != nil {
|
||||
log.Fatalf("LoadGlyph: %v", err)
|
||||
}
|
||||
|
||||
r := vector.NewRasterizer(width, height)
|
||||
r.DrawOp = draw.Src
|
||||
for _, seg := range segments {
|
||||
// The divisions by 64 below is because the seg.Args values have type
|
||||
// fixed.Int26_6, a 26.6 fixed point number, and 1<<6 == 64.
|
||||
switch seg.Op {
|
||||
case sfnt.SegmentOpMoveTo:
|
||||
r.MoveTo(
|
||||
originX+float32(seg.Args[0])/64,
|
||||
originY-float32(seg.Args[1])/64,
|
||||
)
|
||||
case sfnt.SegmentOpLineTo:
|
||||
r.LineTo(
|
||||
originX+float32(seg.Args[0])/64,
|
||||
originY-float32(seg.Args[1])/64,
|
||||
)
|
||||
case sfnt.SegmentOpQuadTo:
|
||||
r.QuadTo(
|
||||
originX+float32(seg.Args[0])/64,
|
||||
originY-float32(seg.Args[1])/64,
|
||||
originX+float32(seg.Args[2])/64,
|
||||
originY-float32(seg.Args[3])/64,
|
||||
)
|
||||
case sfnt.SegmentOpCubeTo:
|
||||
r.CubeTo(
|
||||
originX+float32(seg.Args[0])/64,
|
||||
originY-float32(seg.Args[1])/64,
|
||||
originX+float32(seg.Args[2])/64,
|
||||
originY-float32(seg.Args[3])/64,
|
||||
originX+float32(seg.Args[4])/64,
|
||||
originY-float32(seg.Args[5])/64,
|
||||
)
|
||||
}
|
||||
}
|
||||
// TODO: call ClosePath? Once overall or once per contour (i.e. MoveTo)?
|
||||
|
||||
dst := image.NewAlpha(image.Rect(0, 0, width, height))
|
||||
r.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
|
||||
|
||||
const asciiArt = ".++8"
|
||||
buf := make([]byte, 0, height*(width+1))
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
a := dst.AlphaAt(x, y).A
|
||||
buf = append(buf, asciiArt[a>>6])
|
||||
}
|
||||
buf = append(buf, '\n')
|
||||
}
|
||||
os.Stdout.Write(buf)
|
||||
|
||||
// Output:
|
||||
// ........................
|
||||
// ........................
|
||||
// ........................
|
||||
// ........................
|
||||
// ..........+++++++++.....
|
||||
// .......+8888888888888+..
|
||||
// ......8888888888888888..
|
||||
// ....+8888+........++88..
|
||||
// ....8888................
|
||||
// ...8888.................
|
||||
// ..+888+.................
|
||||
// ..+888..................
|
||||
// ..888+..................
|
||||
// .+888+..................
|
||||
// .+888...................
|
||||
// .+888...................
|
||||
// .+888...................
|
||||
// .+888..........+++++++..
|
||||
// .+888..........8888888..
|
||||
// .+888+.........+++8888..
|
||||
// ..888+............+888..
|
||||
// ..8888............+888..
|
||||
// ..+888+...........+888..
|
||||
// ...8888+..........+888..
|
||||
// ...+8888+.........+888..
|
||||
// ....+88888+.......+888..
|
||||
// .....+8888888888888888..
|
||||
// .......+888888888888++..
|
||||
// ..........++++++++......
|
||||
// ........................
|
||||
// ........................
|
||||
// ........................
|
||||
}
|
||||
321
vendor/golang.org/x/image/font/sfnt/gen.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,321 @@
|
||||
// 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.
|
||||
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data, offsets := []byte(nil), []int{0}
|
||||
for _, name := range names {
|
||||
data = append(data, name...)
|
||||
offsets = append(offsets, len(data))
|
||||
}
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
fmt.Fprintf(b, "// generated by go run gen.go; DO NOT EDIT\n\n")
|
||||
fmt.Fprintf(b, "package sfnt\n\n")
|
||||
|
||||
fmt.Fprintf(b, "const numBuiltInPostNames = %d\n\n", len(names))
|
||||
|
||||
fmt.Fprintf(b, "const builtInPostNamesData = \"\" +\n")
|
||||
for s := data; ; {
|
||||
if len(s) <= 64 {
|
||||
fmt.Fprintf(b, "%q\n", s)
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(b, "%q +\n", s[:64])
|
||||
s = s[64:]
|
||||
}
|
||||
fmt.Fprintf(b, "\n")
|
||||
|
||||
fmt.Fprintf(b, "var builtInPostNamesOffsets = [...]uint16{\n")
|
||||
for i, o := range offsets {
|
||||
fmt.Fprintf(b, "%#04x,", o)
|
||||
if i%8 == 7 {
|
||||
fmt.Fprintf(b, "\n")
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "\n}\n")
|
||||
|
||||
dstUnformatted := b.Bytes()
|
||||
dst, err := format.Source(dstUnformatted)
|
||||
if err != nil {
|
||||
log.Fatalf("format.Source: %v\n\n----\n%s\n----", err, dstUnformatted)
|
||||
}
|
||||
if err := ioutil.WriteFile("data.go", dst, 0666); err != nil {
|
||||
log.Fatalf("ioutil.WriteFile: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// names is the built-in post table names listed at
|
||||
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
|
||||
var names = [258]string{
|
||||
".notdef",
|
||||
".null",
|
||||
"nonmarkingreturn",
|
||||
"space",
|
||||
"exclam",
|
||||
"quotedbl",
|
||||
"numbersign",
|
||||
"dollar",
|
||||
"percent",
|
||||
"ampersand",
|
||||
"quotesingle",
|
||||
"parenleft",
|
||||
"parenright",
|
||||
"asterisk",
|
||||
"plus",
|
||||
"comma",
|
||||
"hyphen",
|
||||
"period",
|
||||
"slash",
|
||||
"zero",
|
||||
"one",
|
||||
"two",
|
||||
"three",
|
||||
"four",
|
||||
"five",
|
||||
"six",
|
||||
"seven",
|
||||
"eight",
|
||||
"nine",
|
||||
"colon",
|
||||
"semicolon",
|
||||
"less",
|
||||
"equal",
|
||||
"greater",
|
||||
"question",
|
||||
"at",
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F",
|
||||
"G",
|
||||
"H",
|
||||
"I",
|
||||
"J",
|
||||
"K",
|
||||
"L",
|
||||
"M",
|
||||
"N",
|
||||
"O",
|
||||
"P",
|
||||
"Q",
|
||||
"R",
|
||||
"S",
|
||||
"T",
|
||||
"U",
|
||||
"V",
|
||||
"W",
|
||||
"X",
|
||||
"Y",
|
||||
"Z",
|
||||
"bracketleft",
|
||||
"backslash",
|
||||
"bracketright",
|
||||
"asciicircum",
|
||||
"underscore",
|
||||
"grave",
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
"e",
|
||||
"f",
|
||||
"g",
|
||||
"h",
|
||||
"i",
|
||||
"j",
|
||||
"k",
|
||||
"l",
|
||||
"m",
|
||||
"n",
|
||||
"o",
|
||||
"p",
|
||||
"q",
|
||||
"r",
|
||||
"s",
|
||||
"t",
|
||||
"u",
|
||||
"v",
|
||||
"w",
|
||||
"x",
|
||||
"y",
|
||||
"z",
|
||||
"braceleft",
|
||||
"bar",
|
||||
"braceright",
|
||||
"asciitilde",
|
||||
"Adieresis",
|
||||
"Aring",
|
||||
"Ccedilla",
|
||||
"Eacute",
|
||||
"Ntilde",
|
||||
"Odieresis",
|
||||
"Udieresis",
|
||||
"aacute",
|
||||
"agrave",
|
||||
"acircumflex",
|
||||
"adieresis",
|
||||
"atilde",
|
||||
"aring",
|
||||
"ccedilla",
|
||||
"eacute",
|
||||
"egrave",
|
||||
"ecircumflex",
|
||||
"edieresis",
|
||||
"iacute",
|
||||
"igrave",
|
||||
"icircumflex",
|
||||
"idieresis",
|
||||
"ntilde",
|
||||
"oacute",
|
||||
"ograve",
|
||||
"ocircumflex",
|
||||
"odieresis",
|
||||
"otilde",
|
||||
"uacute",
|
||||
"ugrave",
|
||||
"ucircumflex",
|
||||
"udieresis",
|
||||
"dagger",
|
||||
"degree",
|
||||
"cent",
|
||||
"sterling",
|
||||
"section",
|
||||
"bullet",
|
||||
"paragraph",
|
||||
"germandbls",
|
||||
"registered",
|
||||
"copyright",
|
||||
"trademark",
|
||||
"acute",
|
||||
"dieresis",
|
||||
"notequal",
|
||||
"AE",
|
||||
"Oslash",
|
||||
"infinity",
|
||||
"plusminus",
|
||||
"lessequal",
|
||||
"greaterequal",
|
||||
"yen",
|
||||
"mu",
|
||||
"partialdiff",
|
||||
"summation",
|
||||
"product",
|
||||
"pi",
|
||||
"integral",
|
||||
"ordfeminine",
|
||||
"ordmasculine",
|
||||
"Omega",
|
||||
"ae",
|
||||
"oslash",
|
||||
"questiondown",
|
||||
"exclamdown",
|
||||
"logicalnot",
|
||||
"radical",
|
||||
"florin",
|
||||
"approxequal",
|
||||
"Delta",
|
||||
"guillemotleft",
|
||||
"guillemotright",
|
||||
"ellipsis",
|
||||
"nonbreakingspace",
|
||||
"Agrave",
|
||||
"Atilde",
|
||||
"Otilde",
|
||||
"OE",
|
||||
"oe",
|
||||
"endash",
|
||||
"emdash",
|
||||
"quotedblleft",
|
||||
"quotedblright",
|
||||
"quoteleft",
|
||||
"quoteright",
|
||||
"divide",
|
||||
"lozenge",
|
||||
"ydieresis",
|
||||
"Ydieresis",
|
||||
"fraction",
|
||||
"currency",
|
||||
"guilsinglleft",
|
||||
"guilsinglright",
|
||||
"fi",
|
||||
"fl",
|
||||
"daggerdbl",
|
||||
"periodcentered",
|
||||
"quotesinglbase",
|
||||
"quotedblbase",
|
||||
"perthousand",
|
||||
"Acircumflex",
|
||||
"Ecircumflex",
|
||||
"Aacute",
|
||||
"Edieresis",
|
||||
"Egrave",
|
||||
"Iacute",
|
||||
"Icircumflex",
|
||||
"Idieresis",
|
||||
"Igrave",
|
||||
"Oacute",
|
||||
"Ocircumflex",
|
||||
"apple",
|
||||
"Ograve",
|
||||
"Uacute",
|
||||
"Ucircumflex",
|
||||
"Ugrave",
|
||||
"dotlessi",
|
||||
"circumflex",
|
||||
"tilde",
|
||||
"macron",
|
||||
"breve",
|
||||
"dotaccent",
|
||||
"ring",
|
||||
"cedilla",
|
||||
"hungarumlaut",
|
||||
"ogonek",
|
||||
"caron",
|
||||
"Lslash",
|
||||
"lslash",
|
||||
"Scaron",
|
||||
"scaron",
|
||||
"Zcaron",
|
||||
"zcaron",
|
||||
"brokenbar",
|
||||
"Eth",
|
||||
"eth",
|
||||
"Yacute",
|
||||
"yacute",
|
||||
"Thorn",
|
||||
"thorn",
|
||||
"minus",
|
||||
"multiply",
|
||||
"onesuperior",
|
||||
"twosuperior",
|
||||
"threesuperior",
|
||||
"onehalf",
|
||||
"onequarter",
|
||||
"threequarters",
|
||||
"franc",
|
||||
"Gbreve",
|
||||
"gbreve",
|
||||
"Idotaccent",
|
||||
"Scedilla",
|
||||
"scedilla",
|
||||
"Cacute",
|
||||
"cacute",
|
||||
"Ccaron",
|
||||
"ccaron",
|
||||
"dcroat",
|
||||
}
|
||||
117
vendor/golang.org/x/image/font/sfnt/postscript.go
сгенерированный
поставляемый
@@ -566,8 +566,8 @@ var psOperators = [...][2][]psOperator{
|
||||
23: {-1, "vstemhm", t2CStem},
|
||||
24: {}, // rcurveline.
|
||||
25: {}, // rlinecurve.
|
||||
26: {}, // vvcurveto.
|
||||
27: {}, // hhcurveto.
|
||||
26: {-1, "vvcurveto", t2CVvcurveto},
|
||||
27: {-1, "hhcurveto", t2CHhcurveto},
|
||||
28: {}, // shortint.
|
||||
29: {}, // callgsubr.
|
||||
30: {-1, "vhcurveto", t2CVhcurveto},
|
||||
@@ -653,8 +653,8 @@ func t2CAppendMoveto(p *psInterpreter) {
|
||||
p.type2Charstrings.segments = append(p.type2Charstrings.segments, Segment{
|
||||
Op: SegmentOpMoveTo,
|
||||
Args: [6]fixed.Int26_6{
|
||||
0: fixed.Int26_6(p.type2Charstrings.x) << 6,
|
||||
1: fixed.Int26_6(p.type2Charstrings.y) << 6,
|
||||
0: fixed.Int26_6(p.type2Charstrings.x),
|
||||
1: fixed.Int26_6(p.type2Charstrings.y),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -663,8 +663,8 @@ func t2CAppendLineto(p *psInterpreter) {
|
||||
p.type2Charstrings.segments = append(p.type2Charstrings.segments, Segment{
|
||||
Op: SegmentOpLineTo,
|
||||
Args: [6]fixed.Int26_6{
|
||||
0: fixed.Int26_6(p.type2Charstrings.x) << 6,
|
||||
1: fixed.Int26_6(p.type2Charstrings.y) << 6,
|
||||
0: fixed.Int26_6(p.type2Charstrings.x),
|
||||
1: fixed.Int26_6(p.type2Charstrings.y),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -685,12 +685,12 @@ func t2CAppendCubeto(p *psInterpreter, dxa, dya, dxb, dyb, dxc, dyc int32) {
|
||||
p.type2Charstrings.segments = append(p.type2Charstrings.segments, Segment{
|
||||
Op: SegmentOpCubeTo,
|
||||
Args: [6]fixed.Int26_6{
|
||||
0: fixed.Int26_6(xa) << 6,
|
||||
1: fixed.Int26_6(ya) << 6,
|
||||
2: fixed.Int26_6(xb) << 6,
|
||||
3: fixed.Int26_6(yb) << 6,
|
||||
4: fixed.Int26_6(xc) << 6,
|
||||
5: fixed.Int26_6(yc) << 6,
|
||||
0: fixed.Int26_6(xa),
|
||||
1: fixed.Int26_6(ya),
|
||||
2: fixed.Int26_6(xb),
|
||||
3: fixed.Int26_6(yb),
|
||||
4: fixed.Int26_6(xc),
|
||||
5: fixed.Int26_6(yc),
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -770,6 +770,12 @@ func t2CRlineto(p *psInterpreter) error {
|
||||
|
||||
// As per 5177.Type2.pdf section 4.1 "Path Construction Operators",
|
||||
//
|
||||
// hhcurveto is:
|
||||
// - dy1 {dxa dxb dyb dxc}+
|
||||
//
|
||||
// vvcurveto is:
|
||||
// - dx1 {dya dxb dyb dyc}+
|
||||
//
|
||||
// hvcurveto is one of:
|
||||
// - dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
|
||||
// - {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
|
||||
@@ -778,59 +784,84 @@ func t2CRlineto(p *psInterpreter) error {
|
||||
// - dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf?
|
||||
// - {dya dxb dyb dxc dxd dxe dye dyf}+ dxf?
|
||||
|
||||
func t2CHvcurveto(p *psInterpreter) error { return t2CCurveto(p, false) }
|
||||
func t2CVhcurveto(p *psInterpreter) error { return t2CCurveto(p, true) }
|
||||
func t2CHhcurveto(p *psInterpreter) error { return t2CCurveto(p, false, false) }
|
||||
func t2CVvcurveto(p *psInterpreter) error { return t2CCurveto(p, false, true) }
|
||||
func t2CHvcurveto(p *psInterpreter) error { return t2CCurveto(p, true, false) }
|
||||
func t2CVhcurveto(p *psInterpreter) error { return t2CCurveto(p, true, true) }
|
||||
|
||||
func t2CCurveto(p *psInterpreter, vertical bool) error {
|
||||
// t2CCurveto implements the hh / vv / hv / vh xxcurveto operators. N relative
|
||||
// cubic curve requires 6*N control points, but only 4*N+0 or 4*N+1 are used
|
||||
// here: all (or all but one) of the piecewise cubic curve's tangents are
|
||||
// implicitly horizontal or vertical.
|
||||
//
|
||||
// swap is whether that implicit horizontal / vertical constraint swaps as you
|
||||
// move along the piecewise cubic curve. If swap is false, the constraints are
|
||||
// either all horizontal or all vertical. If swap is true, it alternates.
|
||||
//
|
||||
// vertical is whether the first implicit constraint is vertical.
|
||||
func t2CCurveto(p *psInterpreter, swap, vertical bool) error {
|
||||
if !p.type2Charstrings.seenWidth || p.stack.top < 4 {
|
||||
return errInvalidCFFTable
|
||||
}
|
||||
for i := int32(0); i != p.stack.top; vertical = !vertical {
|
||||
if vertical {
|
||||
i = t2CVcurveto(p, i)
|
||||
} else {
|
||||
i = t2CHcurveto(p, i)
|
||||
|
||||
i := int32(0)
|
||||
switch p.stack.top & 3 {
|
||||
case 0:
|
||||
// No-op.
|
||||
case 1:
|
||||
if swap {
|
||||
break
|
||||
}
|
||||
i = 1
|
||||
if vertical {
|
||||
p.type2Charstrings.x += p.stack.a[0]
|
||||
} else {
|
||||
p.type2Charstrings.y += p.stack.a[0]
|
||||
}
|
||||
default:
|
||||
return errInvalidCFFTable
|
||||
}
|
||||
|
||||
for i != p.stack.top {
|
||||
i = t2CCurveto4(p, swap, vertical, i)
|
||||
if i < 0 {
|
||||
return errInvalidCFFTable
|
||||
}
|
||||
if swap {
|
||||
vertical = !vertical
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func t2CHcurveto(p *psInterpreter, i int32) (j int32) {
|
||||
func t2CCurveto4(p *psInterpreter, swap bool, vertical bool, i int32) (j int32) {
|
||||
if i+4 > p.stack.top {
|
||||
return -1
|
||||
}
|
||||
dxa := p.stack.a[i+0]
|
||||
dxb := p.stack.a[i+1]
|
||||
dyb := p.stack.a[i+2]
|
||||
dyc := p.stack.a[i+3]
|
||||
dxc := int32(0)
|
||||
i += 4
|
||||
if i+1 == p.stack.top {
|
||||
dxc = p.stack.a[i]
|
||||
i++
|
||||
}
|
||||
t2CAppendCubeto(p, dxa, 0, dxb, dyb, dxc, dyc)
|
||||
return i
|
||||
}
|
||||
|
||||
func t2CVcurveto(p *psInterpreter, i int32) (j int32) {
|
||||
if i+4 > p.stack.top {
|
||||
return -1
|
||||
}
|
||||
dya := p.stack.a[i+0]
|
||||
dya := int32(0)
|
||||
dxb := p.stack.a[i+1]
|
||||
dyb := p.stack.a[i+2]
|
||||
dxc := p.stack.a[i+3]
|
||||
dyc := int32(0)
|
||||
i += 4
|
||||
if i+1 == p.stack.top {
|
||||
dyc = p.stack.a[i]
|
||||
i++
|
||||
|
||||
if vertical {
|
||||
dxa, dya = dya, dxa
|
||||
}
|
||||
t2CAppendCubeto(p, 0, dya, dxb, dyb, dxc, dyc)
|
||||
|
||||
if swap {
|
||||
if i+1 == p.stack.top {
|
||||
dyc = p.stack.a[i]
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
if swap != vertical {
|
||||
dxc, dyc = dyc, dxc
|
||||
}
|
||||
|
||||
t2CAppendCubeto(p, dxa, dya, dxb, dyb, dxc, dyc)
|
||||
return i
|
||||
}
|
||||
|
||||
|
||||
479
vendor/golang.org/x/image/font/sfnt/proprietary_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,479 @@
|
||||
// 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 sfnt
|
||||
|
||||
/*
|
||||
This file contains opt-in tests for popular, high quality, proprietary fonts,
|
||||
made by companies such as Adobe and Microsoft. These fonts are generally
|
||||
available, but copies are not explicitly included in this repository due to
|
||||
licensing differences or file size concerns. To opt-in, run:
|
||||
|
||||
go test golang.org/x/image/font/sfnt -args -proprietary
|
||||
|
||||
Not all tests pass out-of-the-box on all systems. For example, the Microsoft
|
||||
Times New Roman font is downloadable gratis even on non-Windows systems, but as
|
||||
per the ttf-mscorefonts-installer Debian package, this requires accepting an
|
||||
End User License Agreement (EULA) and a CAB format decoder. These tests assume
|
||||
that such fonts have already been installed. You may need to specify the
|
||||
directories for these fonts:
|
||||
|
||||
go test golang.org/x/image/font/sfnt -args -proprietary -adobeDir=/foo/bar/aFonts -microsoftDir=/foo/bar/mFonts
|
||||
|
||||
To only run those tests for the Microsoft fonts:
|
||||
|
||||
go test golang.org/x/image/font/sfnt -test.run=ProprietaryMicrosoft -args -proprietary
|
||||
*/
|
||||
|
||||
// TODO: add Apple system fonts? Google fonts (Droid? Noto?)? Emoji fonts?
|
||||
|
||||
// TODO: enable Apple/Microsoft tests by default on Darwin/Windows?
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
var (
|
||||
proprietary = flag.Bool("proprietary", false, "test proprietary fonts not included in this repository")
|
||||
|
||||
adobeDir = flag.String(
|
||||
"adobeDir",
|
||||
// This needs to be set explicitly. There is no default dir on Debian:
|
||||
// https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=736680
|
||||
//
|
||||
// Get the fonts from https://github.com/adobe-fonts, e.g.:
|
||||
// - https://github.com/adobe-fonts/source-code-pro/releases/latest
|
||||
// - https://github.com/adobe-fonts/source-han-sans/releases/latest
|
||||
// - https://github.com/adobe-fonts/source-sans-pro/releases/latest
|
||||
//
|
||||
// Copy all of the TTF and OTF files to the one directory, such as
|
||||
// $HOME/adobe-fonts, and pass that as the -adobeDir flag here.
|
||||
"",
|
||||
"directory name for the Adobe proprietary fonts",
|
||||
)
|
||||
|
||||
microsoftDir = flag.String(
|
||||
"microsoftDir",
|
||||
"/usr/share/fonts/truetype/msttcorefonts",
|
||||
"directory name for the Microsoft proprietary fonts",
|
||||
)
|
||||
)
|
||||
|
||||
func TestProprietaryAdobeSourceCodeProOTF(t *testing.T) {
|
||||
testProprietary(t, "adobe", "SourceCodePro-Regular.otf", 1500, 2)
|
||||
}
|
||||
|
||||
func TestProprietaryAdobeSourceCodeProTTF(t *testing.T) {
|
||||
testProprietary(t, "adobe", "SourceCodePro-Regular.ttf", 1500, 36)
|
||||
}
|
||||
|
||||
func TestProprietaryAdobeSourceHanSansSC(t *testing.T) {
|
||||
testProprietary(t, "adobe", "SourceHanSansSC-Regular.otf", 65535, 2)
|
||||
}
|
||||
|
||||
func TestProprietaryAdobeSourceSansProOTF(t *testing.T) {
|
||||
testProprietary(t, "adobe", "SourceSansPro-Regular.otf", 1800, 2)
|
||||
}
|
||||
|
||||
func TestProprietaryAdobeSourceSansProTTF(t *testing.T) {
|
||||
testProprietary(t, "adobe", "SourceSansPro-Regular.ttf", 1800, 54)
|
||||
}
|
||||
|
||||
func TestProprietaryMicrosoftArial(t *testing.T) {
|
||||
testProprietary(t, "microsoft", "Arial.ttf", 1200, 98)
|
||||
}
|
||||
|
||||
func TestProprietaryMicrosoftComicSansMS(t *testing.T) {
|
||||
testProprietary(t, "microsoft", "Comic_Sans_MS.ttf", 550, 98)
|
||||
}
|
||||
|
||||
func TestProprietaryMicrosoftTimesNewRoman(t *testing.T) {
|
||||
testProprietary(t, "microsoft", "Times_New_Roman.ttf", 1200, 98)
|
||||
}
|
||||
|
||||
func TestProprietaryMicrosoftWebdings(t *testing.T) {
|
||||
testProprietary(t, "microsoft", "Webdings.ttf", 200, -1)
|
||||
}
|
||||
|
||||
// testProprietary tests that we can load every glyph in the named font.
|
||||
//
|
||||
// The exact number of glyphs in the font can differ across its various
|
||||
// versions, but as a sanity check, there should be at least minNumGlyphs.
|
||||
//
|
||||
// While this package is a work-in-progress, not every glyph can be loaded. The
|
||||
// firstUnsupportedGlyph argument, if non-negative, is the index of the first
|
||||
// unsupported glyph in the font. This number should increase over time (or set
|
||||
// negative), as the TODO's in this package are done.
|
||||
func testProprietary(t *testing.T, proprietor, filename string, minNumGlyphs, firstUnsupportedGlyph int) {
|
||||
if !*proprietary {
|
||||
t.Skip("skipping proprietary font test")
|
||||
}
|
||||
|
||||
file, err := []byte(nil), error(nil)
|
||||
switch proprietor {
|
||||
case "adobe":
|
||||
file, err = ioutil.ReadFile(filepath.Join(*adobeDir, filename))
|
||||
if err != nil {
|
||||
t.Fatalf("%v\nPerhaps you need to set the -adobeDir=%v flag?", err, *adobeDir)
|
||||
}
|
||||
case "microsoft":
|
||||
file, err = ioutil.ReadFile(filepath.Join(*microsoftDir, filename))
|
||||
if err != nil {
|
||||
t.Fatalf("%v\nPerhaps you need to set the -microsoftDir=%v flag?", err, *microsoftDir)
|
||||
}
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
f, err := Parse(file)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse: %v", err)
|
||||
}
|
||||
ppem := fixed.Int26_6(f.UnitsPerEm())
|
||||
qualifiedFilename := proprietor + "/" + filename
|
||||
var buf Buffer
|
||||
|
||||
// Some of the tests below, such as which glyph index a particular rune
|
||||
// maps to, can depend on the specific version of the proprietary font. If
|
||||
// tested against a different version of that font, the test might (but not
|
||||
// necessarily will) fail, even though the Go code is good. If so, log a
|
||||
// message, but don't automatically fail (i.e. dont' call t.Fatalf).
|
||||
gotVersion, err := f.Name(&buf, NameIDVersion)
|
||||
if err != nil {
|
||||
t.Fatalf("Name: %v", err)
|
||||
}
|
||||
wantVersion := proprietaryVersions[qualifiedFilename]
|
||||
if gotVersion != wantVersion {
|
||||
t.Logf("font version provided differs from the one the tests were written against:"+
|
||||
"\ngot %q\nwant %q", gotVersion, wantVersion)
|
||||
}
|
||||
|
||||
numGlyphs := f.NumGlyphs()
|
||||
if numGlyphs < minNumGlyphs {
|
||||
t.Fatalf("NumGlyphs: got %d, want at least %d", numGlyphs, minNumGlyphs)
|
||||
}
|
||||
|
||||
iMax := numGlyphs
|
||||
if firstUnsupportedGlyph >= 0 {
|
||||
iMax = firstUnsupportedGlyph
|
||||
}
|
||||
for i, numErrors := 0, 0; i < iMax; i++ {
|
||||
if _, err := f.LoadGlyph(&buf, GlyphIndex(i), ppem, nil); err != nil {
|
||||
t.Errorf("LoadGlyph(%d): %v", i, err)
|
||||
numErrors++
|
||||
}
|
||||
if numErrors == 10 {
|
||||
t.Fatal("LoadGlyph: too many errors")
|
||||
}
|
||||
}
|
||||
|
||||
for r, want := range proprietaryGlyphIndexTestCases[qualifiedFilename] {
|
||||
got, err := f.GlyphIndex(&buf, r)
|
||||
if err != nil {
|
||||
t.Errorf("GlyphIndex(%q): %v", r, err)
|
||||
continue
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("GlyphIndex(%q): got %d, want %d", r, got, want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for r, want := range proprietaryGlyphTestCases[qualifiedFilename] {
|
||||
x, err := f.GlyphIndex(&buf, r)
|
||||
if err != nil {
|
||||
t.Errorf("GlyphIndex(%q): %v", r, err)
|
||||
continue
|
||||
}
|
||||
got, err := f.LoadGlyph(&buf, x, ppem, nil)
|
||||
if err != nil {
|
||||
t.Errorf("LoadGlyph(%q): %v", r, err)
|
||||
continue
|
||||
}
|
||||
if err := checkSegmentsEqual(got, want); err != nil {
|
||||
t.Errorf("LoadGlyph(%q): %v", r, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
kernLoop:
|
||||
for _, tc := range proprietaryKernTestCases[qualifiedFilename] {
|
||||
var indexes [2]GlyphIndex
|
||||
for i := range indexes {
|
||||
x, err := f.GlyphIndex(&buf, tc.runes[i])
|
||||
if x == 0 && err == nil {
|
||||
err = errors.New("no glyph index found")
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("GlyphIndex(%q): %v", tc.runes[0], err)
|
||||
continue kernLoop
|
||||
}
|
||||
indexes[i] = x
|
||||
}
|
||||
kern, err := f.Kern(&buf, indexes[0], indexes[1], tc.ppem, tc.hinting)
|
||||
if err != nil {
|
||||
t.Errorf("Kern(%q, %q, ppem=%d, hinting=%v): %v",
|
||||
tc.runes[0], tc.runes[1], tc.ppem, tc.hinting, err)
|
||||
continue
|
||||
}
|
||||
if got := Units(kern); got != tc.want {
|
||||
t.Errorf("Kern(%q, %q, ppem=%d, hinting=%v): got %d, want %d",
|
||||
tc.runes[0], tc.runes[1], tc.ppem, tc.hinting, got, tc.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// proprietaryVersions holds the expected version string of each proprietary
|
||||
// font tested. If third parties such as Adobe or Microsoft update their fonts,
|
||||
// and the tests subsequently fail, these versions should be updated too.
|
||||
//
|
||||
// Updates are expected to be infrequent. For example, as of 2017, the fonts
|
||||
// installed by the Debian ttf-mscorefonts-installer package have last modified
|
||||
// times no later than 2001.
|
||||
var proprietaryVersions = map[string]string{
|
||||
"adobe/SourceCodePro-Regular.otf": "Version 2.030;PS 1.0;hotconv 16.6.51;makeotf.lib2.5.65220",
|
||||
"adobe/SourceCodePro-Regular.ttf": "Version 2.030;PS 1.000;hotconv 16.6.51;makeotf.lib2.5.65220",
|
||||
"adobe/SourceHanSansSC-Regular.otf": "Version 1.004;PS 1.004;hotconv 1.0.82;makeotf.lib2.5.63406",
|
||||
"adobe/SourceSansPro-Regular.otf": "Version 2.020;PS 2.0;hotconv 1.0.86;makeotf.lib2.5.63406",
|
||||
"adobe/SourceSansPro-Regular.ttf": "Version 2.020;PS 2.000;hotconv 1.0.86;makeotf.lib2.5.63406",
|
||||
|
||||
"microsoft/Arial.ttf": "Version 2.82",
|
||||
"microsoft/Comic_Sans_MS.ttf": "Version 2.10",
|
||||
"microsoft/Times_New_Roman.ttf": "Version 2.82",
|
||||
"microsoft/Webdings.ttf": "Version 1.03",
|
||||
}
|
||||
|
||||
// proprietaryGlyphIndexTestCases hold a sample of each font's rune to glyph
|
||||
// index cmap. The numerical values can be verified by running the ttx tool.
|
||||
var proprietaryGlyphIndexTestCases = map[string]map[rune]GlyphIndex{
|
||||
"adobe/SourceCodePro-Regular.otf": {
|
||||
'\u0030': 877, // U+0030 DIGIT ZERO
|
||||
'\u0041': 2, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u0061': 28, // U+0061 LATIN SMALL LETTER A
|
||||
'\u0104': 64, // U+0104 LATIN CAPITAL LETTER A WITH OGONEK
|
||||
'\u0125': 323, // U+0125 LATIN SMALL LETTER H WITH CIRCUMFLEX
|
||||
'\u01f4': 111, // U+01F4 LATIN CAPITAL LETTER G WITH ACUTE
|
||||
'\u03a3': 623, // U+03A3 GREEK CAPITAL LETTER SIGMA
|
||||
'\u2569': 1500, // U+2569 BOX DRAWINGS DOUBLE UP AND HORIZONTAL
|
||||
'\U0001f100': 0, // U+0001F100 DIGIT ZERO FULL STOP
|
||||
},
|
||||
"adobe/SourceCodePro-Regular.ttf": {
|
||||
'\u0030': 877, // U+0030 DIGIT ZERO
|
||||
'\u0041': 2, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u01f4': 111, // U+01F4 LATIN CAPITAL LETTER G WITH ACUTE
|
||||
},
|
||||
"adobe/SourceHanSansSC-Regular.otf": {
|
||||
'\u0030': 17, // U+0030 DIGIT ZERO
|
||||
'\u0041': 34, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u00d7': 150, // U+00D7 MULTIPLICATION SIGN
|
||||
'\u1100': 365, // U+1100 HANGUL CHOSEONG KIYEOK
|
||||
'\u25ca': 1254, // U+25CA LOZENGE
|
||||
'\u2e9c': 1359, // U+2E9C CJK RADICAL SUN
|
||||
'\u304b': 1463, // U+304B HIRAGANA LETTER KA
|
||||
'\u4e2d': 9893, // U+4E2D <CJK Ideograph>, 中
|
||||
'\ua960': 47537, // U+A960 HANGUL CHOSEONG TIKEUT-MIEUM
|
||||
'\ufb00': 58919, // U+FB00 LATIN SMALL LIGATURE FF
|
||||
'\uffee': 59213, // U+FFEE HALFWIDTH WHITE CIRCLE
|
||||
'\U0001f100': 59214, // U+0001F100 DIGIT ZERO FULL STOP
|
||||
'\U0001f248': 59449, // U+0001F248 TORTOISE SHELL BRACKETED CJK UNIFIED IDEOGRAPH-6557
|
||||
'\U0002f9f4': 61768, // U+0002F9F4 CJK COMPATIBILITY IDEOGRAPH-2F9F4
|
||||
},
|
||||
"adobe/SourceSansPro-Regular.otf": {
|
||||
'\u0041': 2, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u03a3': 592, // U+03A3 GREEK CAPITAL LETTER SIGMA
|
||||
'\u0435': 999, // U+0435 CYRILLIC SMALL LETTER IE
|
||||
'\u2030': 1728, // U+2030 PER MILLE SIGN
|
||||
},
|
||||
"adobe/SourceSansPro-Regular.ttf": {
|
||||
'\u0041': 2, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u03a3': 592, // U+03A3 GREEK CAPITAL LETTER SIGMA
|
||||
'\u0435': 999, // U+0435 CYRILLIC SMALL LETTER IE
|
||||
'\u2030': 1728, // U+2030 PER MILLE SIGN
|
||||
},
|
||||
|
||||
"microsoft/Arial.ttf": {
|
||||
'\u0041': 36, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u00f1': 120, // U+00F1 LATIN SMALL LETTER N WITH TILDE
|
||||
'\u0401': 556, // U+0401 CYRILLIC CAPITAL LETTER IO
|
||||
'\u200d': 745, // U+200D ZERO WIDTH JOINER
|
||||
'\u20ab': 1150, // U+20AB DONG SIGN
|
||||
'\u2229': 320, // U+2229 INTERSECTION
|
||||
'\u04e9': 1319, // U+04E9 CYRILLIC SMALL LETTER BARRED O
|
||||
'\U0001f100': 0, // U+0001F100 DIGIT ZERO FULL STOP
|
||||
},
|
||||
"microsoft/Comic_Sans_MS.ttf": {
|
||||
'\u0041': 36, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u03af': 573, // U+03AF GREEK SMALL LETTER IOTA WITH TONOS
|
||||
},
|
||||
"microsoft/Times_New_Roman.ttf": {
|
||||
'\u0041': 36, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u0042': 37, // U+0041 LATIN CAPITAL LETTER B
|
||||
'\u266a': 392, // U+266A EIGHTH NOTE
|
||||
'\uf041': 0, // PRIVATE USE AREA
|
||||
'\uf042': 0, // PRIVATE USE AREA
|
||||
},
|
||||
"microsoft/Webdings.ttf": {
|
||||
'\u0041': 0, // U+0041 LATIN CAPITAL LETTER A
|
||||
'\u0042': 0, // U+0041 LATIN CAPITAL LETTER B
|
||||
'\u266a': 0, // U+266A EIGHTH NOTE
|
||||
'\uf041': 36, // PRIVATE USE AREA
|
||||
'\uf042': 37, // PRIVATE USE AREA
|
||||
},
|
||||
}
|
||||
|
||||
// proprietaryGlyphTestCases hold a sample of each font's glyph vectors. The
|
||||
// numerical values can be verified by running the ttx tool, remembering that:
|
||||
// - for PostScript glyphs, ttx coordinates are relative, and hstem / vstem
|
||||
// operators are hinting-related and can be ignored.
|
||||
// - for TrueType glyphs, ttx coordinates are absolute, and consecutive
|
||||
// off-curve points implies an on-curve point at the midpoint.
|
||||
var proprietaryGlyphTestCases = map[string]map[rune][]Segment{
|
||||
"adobe/SourceSansPro-Regular.otf": {
|
||||
',': {
|
||||
// - contour #0
|
||||
// 67 -170 rmoveto
|
||||
moveTo(67, -170),
|
||||
// 81 34 50 67 86 vvcurveto
|
||||
cubeTo(148, -136, 198, -69, 198, 17),
|
||||
// 60 -26 37 -43 -33 -28 -22 -36 -37 27 -20 32 3 4 0 1 3 vhcurveto
|
||||
cubeTo(198, 77, 172, 114, 129, 114),
|
||||
cubeTo(96, 114, 68, 92, 68, 56),
|
||||
cubeTo(68, 19, 95, -1, 127, -1),
|
||||
cubeTo(130, -1, 134, -1, 137, 0),
|
||||
// 1 -53 -34 -44 -57 -25 rrcurveto
|
||||
cubeTo(138, -53, 104, -97, 47, -122),
|
||||
},
|
||||
'Q': {
|
||||
// - contour #0
|
||||
// 332 57 rmoveto
|
||||
moveTo(332, 57),
|
||||
// -117 -77 106 168 163 77 101 117 117 77 -101 -163 -168 -77 -106 -117 hvcurveto
|
||||
cubeTo(215, 57, 138, 163, 138, 331),
|
||||
cubeTo(138, 494, 215, 595, 332, 595),
|
||||
cubeTo(449, 595, 526, 494, 526, 331),
|
||||
cubeTo(526, 163, 449, 57, 332, 57),
|
||||
// - contour #1
|
||||
// 201 -222 rmoveto
|
||||
moveTo(533, -165),
|
||||
// 39 35 7 8 20 hvcurveto
|
||||
cubeTo(572, -165, 607, -158, 627, -150),
|
||||
// -16 64 rlineto
|
||||
lineTo(611, -86),
|
||||
// -5 -18 -22 -4 -29 hhcurveto
|
||||
cubeTo(593, -91, 571, -95, 542, -95),
|
||||
// -71 -60 29 58 -30 hvcurveto
|
||||
cubeTo(471, -95, 411, -66, 381, -8),
|
||||
// 139 24 93 126 189 vvcurveto
|
||||
cubeTo(520, 16, 613, 142, 613, 331),
|
||||
// 209 -116 128 -165 -165 -115 -127 -210 -193 96 -127 143 -20 vhcurveto
|
||||
cubeTo(613, 540, 497, 668, 332, 668),
|
||||
cubeTo(167, 668, 52, 541, 52, 331),
|
||||
cubeTo(52, 138, 148, 11, 291, -9),
|
||||
// -90 38 83 -66 121 hhcurveto
|
||||
cubeTo(329, -99, 412, -165, 533, -165),
|
||||
},
|
||||
},
|
||||
|
||||
"microsoft/Arial.ttf": {
|
||||
',': {
|
||||
// - contour #0
|
||||
moveTo(182, 0),
|
||||
lineTo(182, 205),
|
||||
lineTo(387, 205),
|
||||
lineTo(387, 0),
|
||||
quadTo(387, -113, 347, -182),
|
||||
quadTo(307, -252, 220, -290),
|
||||
lineTo(170, -213),
|
||||
quadTo(227, -188, 254, -139),
|
||||
quadTo(281, -91, 284, 0),
|
||||
lineTo(182, 0),
|
||||
},
|
||||
'i': {
|
||||
// - contour #0
|
||||
moveTo(136, 1259),
|
||||
lineTo(136, 1466),
|
||||
lineTo(316, 1466),
|
||||
lineTo(316, 1259),
|
||||
lineTo(136, 1259),
|
||||
// - contour #1
|
||||
moveTo(136, 0),
|
||||
lineTo(136, 1062),
|
||||
lineTo(316, 1062),
|
||||
lineTo(316, 0),
|
||||
lineTo(136, 0),
|
||||
},
|
||||
'o': {
|
||||
// - contour #0
|
||||
moveTo(68, 531),
|
||||
quadTo(68, 826, 232, 968),
|
||||
quadTo(369, 1086, 566, 1086),
|
||||
quadTo(785, 1086, 924, 942),
|
||||
quadTo(1063, 799, 1063, 546),
|
||||
quadTo(1063, 341, 1001, 223),
|
||||
quadTo(940, 106, 822, 41),
|
||||
quadTo(705, -24, 566, -24),
|
||||
quadTo(343, -24, 205, 119),
|
||||
quadTo(68, 262, 68, 531),
|
||||
// - contour #1
|
||||
moveTo(253, 531),
|
||||
quadTo(253, 327, 342, 225),
|
||||
quadTo(431, 124, 566, 124),
|
||||
quadTo(700, 124, 789, 226),
|
||||
quadTo(878, 328, 878, 537),
|
||||
quadTo(878, 734, 788, 835),
|
||||
quadTo(699, 937, 566, 937),
|
||||
quadTo(431, 937, 342, 836),
|
||||
quadTo(253, 735, 253, 531),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type kernTestCase struct {
|
||||
ppem fixed.Int26_6
|
||||
hinting font.Hinting
|
||||
runes [2]rune
|
||||
want Units
|
||||
}
|
||||
|
||||
// proprietaryKernTestCases hold a sample of each font's kerning pairs. The
|
||||
// numerical values can be verified by running the ttx tool.
|
||||
var proprietaryKernTestCases = map[string][]kernTestCase{
|
||||
"microsoft/Arial.ttf": {
|
||||
{2048, font.HintingNone, [2]rune{'A', 'V'}, -152},
|
||||
// U+03B8 GREEK SMALL LETTER THETA
|
||||
// U+03BB GREEK SMALL LETTER LAMDA
|
||||
{2048, font.HintingNone, [2]rune{'\u03b8', '\u03bb'}, -39},
|
||||
{2048, font.HintingNone, [2]rune{'\u03bb', '\u03b8'}, -0},
|
||||
},
|
||||
"microsoft/Comic_Sans_MS.ttf": {
|
||||
{2048, font.HintingNone, [2]rune{'A', 'V'}, 0},
|
||||
},
|
||||
"microsoft/Times_New_Roman.ttf": {
|
||||
{768, font.HintingNone, [2]rune{'A', 'V'}, -99},
|
||||
{768, font.HintingFull, [2]rune{'A', 'V'}, -128},
|
||||
{2048, font.HintingNone, [2]rune{'A', 'A'}, 0},
|
||||
{2048, font.HintingNone, [2]rune{'A', 'T'}, -227},
|
||||
{2048, font.HintingNone, [2]rune{'A', 'V'}, -264},
|
||||
{2048, font.HintingNone, [2]rune{'T', 'A'}, -164},
|
||||
{2048, font.HintingNone, [2]rune{'T', 'T'}, 0},
|
||||
{2048, font.HintingNone, [2]rune{'T', 'V'}, 0},
|
||||
{2048, font.HintingNone, [2]rune{'V', 'A'}, -264},
|
||||
{2048, font.HintingNone, [2]rune{'V', 'T'}, 0},
|
||||
{2048, font.HintingNone, [2]rune{'V', 'V'}, 0},
|
||||
// U+0390 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
|
||||
// U+0393 GREEK CAPITAL LETTER GAMMA
|
||||
{2048, font.HintingNone, [2]rune{'\u0390', '\u0393'}, 0},
|
||||
{2048, font.HintingNone, [2]rune{'\u0393', '\u0390'}, 76},
|
||||
},
|
||||
"microsoft/Webdings.ttf": {
|
||||
{2048, font.HintingNone, [2]rune{'\uf041', '\uf042'}, 0},
|
||||
},
|
||||
}
|
||||
571
vendor/golang.org/x/image/font/sfnt/sfnt.go
сгенерированный
поставляемый
@@ -2,6 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:generate go run gen.go
|
||||
|
||||
// Package sfnt implements a decoder for SFNT font file formats, including
|
||||
// TrueType and OpenType.
|
||||
package sfnt // import "golang.org/x/image/font/sfnt"
|
||||
@@ -13,11 +15,15 @@ package sfnt // import "golang.org/x/image/font/sfnt"
|
||||
//
|
||||
// The pyftinspect tool from https://github.com/fonttools/fonttools is useful
|
||||
// for inspecting SFNT fonts.
|
||||
//
|
||||
// The ttfdump tool is also useful. For example:
|
||||
// ttfdump -t cmap ../testdata/CFFTest.otf dump.txt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"golang.org/x/image/font"
|
||||
"golang.org/x/image/math/fixed"
|
||||
"golang.org/x/text/encoding/charmap"
|
||||
)
|
||||
@@ -25,6 +31,20 @@ import (
|
||||
// These constants are not part of the specifications, but are limitations used
|
||||
// by this implementation.
|
||||
const (
|
||||
// This value is arbitrary, but defends against parsing malicious font
|
||||
// files causing excessive memory allocations. For reference, Adobe's
|
||||
// SourceHanSansSC-Regular.otf has 65535 glyphs and:
|
||||
// - its format-4 cmap table has 1581 segments.
|
||||
// - its format-12 cmap table has 16498 segments.
|
||||
//
|
||||
// TODO: eliminate this constraint? If the cmap table is very large, load
|
||||
// some or all of it lazily (at the time Font.GlyphIndex is called) instead
|
||||
// of all of it eagerly (at the time Font.initialize is called), while
|
||||
// keeping an upper bound on the memory used? This will make the code in
|
||||
// cmap.go more complicated, considering that all of the Font methods are
|
||||
// safe to call concurrently, as long as each call has a different *Buffer.
|
||||
maxCmapSegments = 20000
|
||||
|
||||
maxGlyphDataLength = 64 * 1024
|
||||
maxHintBits = 256
|
||||
maxNumTables = 256
|
||||
@@ -41,27 +61,34 @@ var (
|
||||
|
||||
errInvalidBounds = errors.New("sfnt: invalid bounds")
|
||||
errInvalidCFFTable = errors.New("sfnt: invalid CFF table")
|
||||
errInvalidCmapTable = errors.New("sfnt: invalid cmap table")
|
||||
errInvalidGlyphData = errors.New("sfnt: invalid glyph data")
|
||||
errInvalidHeadTable = errors.New("sfnt: invalid head table")
|
||||
errInvalidKernTable = errors.New("sfnt: invalid kern table")
|
||||
errInvalidLocaTable = errors.New("sfnt: invalid loca table")
|
||||
errInvalidLocationData = errors.New("sfnt: invalid location data")
|
||||
errInvalidMaxpTable = errors.New("sfnt: invalid maxp table")
|
||||
errInvalidNameTable = errors.New("sfnt: invalid name table")
|
||||
errInvalidPostTable = errors.New("sfnt: invalid post table")
|
||||
errInvalidSourceData = errors.New("sfnt: invalid source data")
|
||||
errInvalidTableOffset = errors.New("sfnt: invalid table offset")
|
||||
errInvalidTableTagOrder = errors.New("sfnt: invalid table tag order")
|
||||
errInvalidUCS2String = errors.New("sfnt: invalid UCS-2 string")
|
||||
errInvalidVersion = errors.New("sfnt: invalid version")
|
||||
|
||||
errUnsupportedCFFVersion = errors.New("sfnt: unsupported CFF version")
|
||||
errUnsupportedCompoundGlyph = errors.New("sfnt: unsupported compound glyph")
|
||||
errUnsupportedGlyphDataLength = errors.New("sfnt: unsupported glyph data length")
|
||||
errUnsupportedRealNumberEncoding = errors.New("sfnt: unsupported real number encoding")
|
||||
errUnsupportedNumberOfHints = errors.New("sfnt: unsupported number of hints")
|
||||
errUnsupportedNumberOfTables = errors.New("sfnt: unsupported number of tables")
|
||||
errUnsupportedPlatformEncoding = errors.New("sfnt: unsupported platform encoding")
|
||||
errUnsupportedTableOffsetLength = errors.New("sfnt: unsupported table offset or length")
|
||||
errUnsupportedType2Charstring = errors.New("sfnt: unsupported Type 2 Charstring")
|
||||
errUnsupportedCFFVersion = errors.New("sfnt: unsupported CFF version")
|
||||
errUnsupportedCmapEncodings = errors.New("sfnt: unsupported cmap encodings")
|
||||
errUnsupportedCompoundGlyph = errors.New("sfnt: unsupported compound glyph")
|
||||
errUnsupportedGlyphDataLength = errors.New("sfnt: unsupported glyph data length")
|
||||
errUnsupportedKernTable = errors.New("sfnt: unsupported kern table")
|
||||
errUnsupportedRealNumberEncoding = errors.New("sfnt: unsupported real number encoding")
|
||||
errUnsupportedNumberOfCmapSegments = errors.New("sfnt: unsupported number of cmap segments")
|
||||
errUnsupportedNumberOfHints = errors.New("sfnt: unsupported number of hints")
|
||||
errUnsupportedNumberOfTables = errors.New("sfnt: unsupported number of tables")
|
||||
errUnsupportedPlatformEncoding = errors.New("sfnt: unsupported platform encoding")
|
||||
errUnsupportedPostTable = errors.New("sfnt: unsupported post table")
|
||||
errUnsupportedTableOffsetLength = errors.New("sfnt: unsupported table offset or length")
|
||||
errUnsupportedType2Charstring = errors.New("sfnt: unsupported Type 2 Charstring")
|
||||
)
|
||||
|
||||
// GlyphIndex is a glyph index in a Font.
|
||||
@@ -107,16 +134,16 @@ const (
|
||||
// display resolution (DPI) and font size (e.g. a 12 point font).
|
||||
type Units int32
|
||||
|
||||
// Platform IDs and Platform Specific IDs as per
|
||||
// https://www.microsoft.com/typography/otspec/name.htm
|
||||
const (
|
||||
pidMacintosh = 1
|
||||
pidWindows = 3
|
||||
|
||||
psidMacintoshRoman = 0
|
||||
|
||||
psidWindowsUCS2 = 1
|
||||
)
|
||||
// scale returns x divided by unitsPerEm, rounded to the nearest fixed.Int26_6
|
||||
// value (1/64th of a pixel).
|
||||
func scale(x fixed.Int26_6, unitsPerEm Units) fixed.Int26_6 {
|
||||
if x >= 0 {
|
||||
x += fixed.Int26_6(unitsPerEm) / 2
|
||||
} else {
|
||||
x -= fixed.Int26_6(unitsPerEm) / 2
|
||||
}
|
||||
return x / fixed.Int26_6(unitsPerEm)
|
||||
}
|
||||
|
||||
func u16(b []byte) uint16 {
|
||||
_ = b[1] // Bounds check hint to compiler.
|
||||
@@ -208,6 +235,20 @@ func (s *source) u16(buf []byte, t table, i int) (uint16, error) {
|
||||
return u16(buf), nil
|
||||
}
|
||||
|
||||
// u32 returns the uint32 in the table t at the relative offset i.
|
||||
//
|
||||
// buf is an optional scratch buffer as per the source.view method.
|
||||
func (s *source) u32(buf []byte, t table, i int) (uint32, error) {
|
||||
if i < 0 || uint(t.length) < uint(i+4) {
|
||||
return 0, errInvalidBounds
|
||||
}
|
||||
buf, err := s.view(buf, int(t.offset)+i, 4)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return u32(buf), nil
|
||||
}
|
||||
|
||||
// table is a section of the font data.
|
||||
type table struct {
|
||||
offset, length uint32
|
||||
@@ -247,6 +288,18 @@ func ParseReaderAt(src io.ReaderAt) (*Font, error) {
|
||||
//
|
||||
// The Font methods that don't take a *Buffer argument are always safe to call
|
||||
// concurrently.
|
||||
//
|
||||
// Some methods provide lengths or coordinates, e.g. bounds, font metrics and
|
||||
// control points. All of these methods take a ppem parameter, which is the
|
||||
// number of pixels in 1 em, expressed as a 26.6 fixed point value. For
|
||||
// example, if 1 em is 10 pixels then ppem is fixed.I(10), which equals
|
||||
// fixed.Int26_6(10 << 6).
|
||||
//
|
||||
// To get those lengths or coordinates in terms of font units instead of
|
||||
// pixels, use ppem = fixed.Int26_6(f.UnitsPerEm()) and if those methods take a
|
||||
// font.Hinting parameter, use font.HintingNone. The return values will have
|
||||
// type fixed.Int26_6, but those numbers can be converted back to Units with no
|
||||
// further scaling necessary.
|
||||
type Font struct {
|
||||
src source
|
||||
|
||||
@@ -283,11 +336,16 @@ type Font struct {
|
||||
// https://www.microsoft.com/typography/otspec/otff.htm#otttables
|
||||
// "Other OpenType Tables".
|
||||
//
|
||||
// TODO: hdmx, kern, vmtx? Others?
|
||||
// TODO: hdmx, vmtx? Others?
|
||||
kern table
|
||||
|
||||
cached struct {
|
||||
glyphIndex glyphIndexFunc
|
||||
indexToLocFormat bool // false means short, true means long.
|
||||
isPostScript bool
|
||||
kernNumPairs int32
|
||||
kernOffset int32
|
||||
postTableVersion uint32
|
||||
unitsPerEm Units
|
||||
|
||||
// The glyph data for the glyph index i is in
|
||||
@@ -306,51 +364,96 @@ func (f *Font) initialize() error {
|
||||
if !f.src.valid() {
|
||||
return errInvalidSourceData
|
||||
}
|
||||
var buf []byte
|
||||
|
||||
// https://www.microsoft.com/typography/otspec/otff.htm "Organization of an
|
||||
// OpenType Font" says that "The OpenType font starts with the Offset
|
||||
// Table", which is 12 bytes.
|
||||
buf, err := f.src.view(buf, 0, 12)
|
||||
buf, isPostScript, err := f.initializeTables(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The order of these parseXxx calls matters. Later calls may depend on
|
||||
// information parsed by earlier calls, such as the maxp table's numGlyphs.
|
||||
// To enforce these dependencies, such information is passed and returned
|
||||
// explicitly, and the f.cached fields are only set afterwards.
|
||||
//
|
||||
// When implementing new parseXxx methods, take care not to call methods
|
||||
// such as Font.NumGlyphs that implicitly depend on f.cached fields.
|
||||
|
||||
buf, indexToLocFormat, unitsPerEm, err := f.parseHead(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, numGlyphs, locations, err := f.parseMaxp(buf, indexToLocFormat, isPostScript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, glyphIndex, err := f.parseCmap(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, kernNumPairs, kernOffset, err := f.parseKern(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf, postTableVersion, err := f.parsePost(buf, numGlyphs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
f.cached.glyphIndex = glyphIndex
|
||||
f.cached.indexToLocFormat = indexToLocFormat
|
||||
f.cached.isPostScript = isPostScript
|
||||
f.cached.kernNumPairs = kernNumPairs
|
||||
f.cached.kernOffset = kernOffset
|
||||
f.cached.postTableVersion = postTableVersion
|
||||
f.cached.unitsPerEm = unitsPerEm
|
||||
f.cached.locations = locations
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *Font) initializeTables(buf []byte) (buf1 []byte, isPostScript bool, err error) {
|
||||
// https://www.microsoft.com/typography/otspec/otff.htm "Organization of an
|
||||
// OpenType Font" says that "The OpenType font starts with the Offset
|
||||
// Table", which is 12 bytes.
|
||||
buf, err = f.src.view(buf, 0, 12)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
switch u32(buf) {
|
||||
default:
|
||||
return errInvalidVersion
|
||||
return nil, false, errInvalidVersion
|
||||
case 0x00010000:
|
||||
// No-op.
|
||||
case 0x4f54544f: // "OTTO".
|
||||
f.cached.isPostScript = true
|
||||
isPostScript = true
|
||||
}
|
||||
numTables := int(u16(buf[4:]))
|
||||
if numTables > maxNumTables {
|
||||
return errUnsupportedNumberOfTables
|
||||
return nil, false, errUnsupportedNumberOfTables
|
||||
}
|
||||
|
||||
// "The Offset Table is followed immediately by the Table Record entries...
|
||||
// sorted in ascending order by tag", 16 bytes each.
|
||||
buf, err = f.src.view(buf, 12, 16*numTables)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, false, err
|
||||
}
|
||||
for b, first, prevTag := buf, true, uint32(0); len(b) > 0; b = b[16:] {
|
||||
tag := u32(b)
|
||||
if first {
|
||||
first = false
|
||||
} else if tag <= prevTag {
|
||||
return errInvalidTableTagOrder
|
||||
return nil, false, errInvalidTableTagOrder
|
||||
}
|
||||
prevTag = tag
|
||||
|
||||
o, n := u32(b[8:12]), u32(b[12:16])
|
||||
if o > maxTableOffset || n > maxTableLength {
|
||||
return errUnsupportedTableOffsetLength
|
||||
return nil, false, errUnsupportedTableOffsetLength
|
||||
}
|
||||
// We ignore the checksums, but "all tables must begin on four byte
|
||||
// boundries [sic]".
|
||||
if o&3 != 0 {
|
||||
return errInvalidTableOffset
|
||||
return nil, false, errInvalidTableOffset
|
||||
}
|
||||
|
||||
// Match the 4-byte tag as a uint32. For example, "OS/2" is 0x4f532f32.
|
||||
@@ -369,6 +472,8 @@ func (f *Font) initialize() error {
|
||||
f.hhea = table{o, n}
|
||||
case 0x686d7478:
|
||||
f.hmtx = table{o, n}
|
||||
case 0x6b65726e:
|
||||
f.kern = table{o, n}
|
||||
case 0x6c6f6361:
|
||||
f.loca = table{o, n}
|
||||
case 0x6d617870:
|
||||
@@ -379,69 +484,258 @@ func (f *Font) initialize() error {
|
||||
f.post = table{o, n}
|
||||
}
|
||||
}
|
||||
return buf, isPostScript, nil
|
||||
}
|
||||
|
||||
var u uint16
|
||||
func (f *Font) parseCmap(buf []byte) (buf1 []byte, glyphIndex glyphIndexFunc, err error) {
|
||||
// https://www.microsoft.com/typography/OTSPEC/cmap.htm
|
||||
|
||||
// https://www.microsoft.com/typography/otspec/head.htm
|
||||
if f.head.length != 54 {
|
||||
return errInvalidHeadTable
|
||||
const headerSize, entrySize = 4, 8
|
||||
if f.cmap.length < headerSize {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
u, err = f.src.u16(buf, f.head, 18)
|
||||
u, err := f.src.u16(buf, f.cmap, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, nil, err
|
||||
}
|
||||
numSubtables := int(u)
|
||||
if f.cmap.length < headerSize+entrySize*uint32(numSubtables) {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
|
||||
var (
|
||||
bestWidth int
|
||||
bestOffset uint32
|
||||
bestLength uint32
|
||||
bestFormat uint16
|
||||
)
|
||||
|
||||
// Scan all of the subtables, picking the widest supported one. See the
|
||||
// platformEncodingWidth comment for more discussion of width.
|
||||
for i := 0; i < numSubtables; i++ {
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset)+headerSize+entrySize*i, entrySize)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pid := u16(buf)
|
||||
psid := u16(buf[2:])
|
||||
width := platformEncodingWidth(pid, psid)
|
||||
if width <= bestWidth {
|
||||
continue
|
||||
}
|
||||
offset := u32(buf[4:])
|
||||
|
||||
if offset > f.cmap.length-4 {
|
||||
return nil, nil, errInvalidCmapTable
|
||||
}
|
||||
buf, err = f.src.view(buf, int(f.cmap.offset+offset), 4)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
format := u16(buf)
|
||||
if !supportedCmapFormat(format, pid, psid) {
|
||||
continue
|
||||
}
|
||||
length := uint32(u16(buf[2:]))
|
||||
|
||||
bestWidth = width
|
||||
bestOffset = offset
|
||||
bestLength = length
|
||||
bestFormat = format
|
||||
}
|
||||
|
||||
if bestWidth == 0 {
|
||||
return nil, nil, errUnsupportedCmapEncodings
|
||||
}
|
||||
return f.makeCachedGlyphIndex(buf, bestOffset, bestLength, bestFormat)
|
||||
}
|
||||
|
||||
func (f *Font) parseHead(buf []byte) (buf1 []byte, indexToLocFormat bool, unitsPerEm Units, err error) {
|
||||
// https://www.microsoft.com/typography/otspec/head.htm
|
||||
|
||||
if f.head.length != 54 {
|
||||
return nil, false, 0, errInvalidHeadTable
|
||||
}
|
||||
u, err := f.src.u16(buf, f.head, 18)
|
||||
if err != nil {
|
||||
return nil, false, 0, err
|
||||
}
|
||||
if u == 0 {
|
||||
return errInvalidHeadTable
|
||||
return nil, false, 0, errInvalidHeadTable
|
||||
}
|
||||
f.cached.unitsPerEm = Units(u)
|
||||
unitsPerEm = Units(u)
|
||||
u, err = f.src.u16(buf, f.head, 50)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, false, 0, err
|
||||
}
|
||||
f.cached.indexToLocFormat = u != 0
|
||||
indexToLocFormat = u != 0
|
||||
return buf, indexToLocFormat, unitsPerEm, nil
|
||||
}
|
||||
|
||||
func (f *Font) parseKern(buf []byte) (buf1 []byte, kernNumPairs, kernOffset int32, err error) {
|
||||
// https://www.microsoft.com/typography/otspec/kern.htm
|
||||
|
||||
if f.kern.length == 0 {
|
||||
return buf, 0, 0, nil
|
||||
}
|
||||
const headerSize = 4
|
||||
if f.kern.length < headerSize {
|
||||
return nil, 0, 0, errInvalidKernTable
|
||||
}
|
||||
buf, err = f.src.view(buf, int(f.kern.offset), headerSize)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
offset := int(f.kern.offset) + headerSize
|
||||
length := int(f.kern.length) - headerSize
|
||||
|
||||
switch version := u16(buf); version {
|
||||
case 0:
|
||||
// TODO: support numTables != 1. Testing that requires finding such a font.
|
||||
if numTables := int(u16(buf[2:])); numTables != 1 {
|
||||
return nil, 0, 0, errUnsupportedKernTable
|
||||
}
|
||||
return f.parseKernVersion0(buf, offset, length)
|
||||
case 1:
|
||||
// TODO: find such a (proprietary?) font, and support it. Both of
|
||||
// https://www.microsoft.com/typography/otspec/kern.htm
|
||||
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kern.html
|
||||
// say that such fonts work on Mac OS but not on Windows.
|
||||
}
|
||||
return nil, 0, 0, errUnsupportedKernTable
|
||||
}
|
||||
|
||||
func (f *Font) parseKernVersion0(buf []byte, offset, length int) (buf1 []byte, kernNumPairs, kernOffset int32, err error) {
|
||||
const headerSize = 6
|
||||
if length < headerSize {
|
||||
return nil, 0, 0, errInvalidKernTable
|
||||
}
|
||||
buf, err = f.src.view(buf, offset, headerSize)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
if version := u16(buf); version != 0 {
|
||||
return nil, 0, 0, errUnsupportedKernTable
|
||||
}
|
||||
subtableLength := int(u16(buf[2:]))
|
||||
if subtableLength < headerSize || length < subtableLength {
|
||||
return nil, 0, 0, errInvalidKernTable
|
||||
}
|
||||
if coverageBits := buf[5]; coverageBits != 0x01 {
|
||||
// We only support horizontal kerning.
|
||||
return nil, 0, 0, errUnsupportedKernTable
|
||||
}
|
||||
offset += headerSize
|
||||
length -= headerSize
|
||||
subtableLength -= headerSize
|
||||
|
||||
switch format := buf[4]; format {
|
||||
case 0:
|
||||
return f.parseKernFormat0(buf, offset, subtableLength)
|
||||
case 2:
|
||||
// TODO: find such a (proprietary?) font, and support it.
|
||||
}
|
||||
return nil, 0, 0, errUnsupportedKernTable
|
||||
}
|
||||
|
||||
func (f *Font) parseKernFormat0(buf []byte, offset, length int) (buf1 []byte, kernNumPairs, kernOffset int32, err error) {
|
||||
const headerSize, entrySize = 8, 6
|
||||
if length < headerSize {
|
||||
return nil, 0, 0, errInvalidKernTable
|
||||
}
|
||||
buf, err = f.src.view(buf, offset, headerSize)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
kernNumPairs = int32(u16(buf))
|
||||
if length != headerSize+entrySize*int(kernNumPairs) {
|
||||
return nil, 0, 0, errInvalidKernTable
|
||||
}
|
||||
return buf, kernNumPairs, int32(offset) + headerSize, nil
|
||||
}
|
||||
|
||||
func (f *Font) parseMaxp(buf []byte, indexToLocFormat, isPostScript bool) (buf1 []byte, numGlyphs int, locations []uint32, err error) {
|
||||
// https://www.microsoft.com/typography/otspec/maxp.htm
|
||||
if f.cached.isPostScript {
|
||||
|
||||
if isPostScript {
|
||||
if f.maxp.length != 6 {
|
||||
return errInvalidMaxpTable
|
||||
return nil, 0, nil, errInvalidMaxpTable
|
||||
}
|
||||
} else {
|
||||
if f.maxp.length != 32 {
|
||||
return errInvalidMaxpTable
|
||||
return nil, 0, nil, errInvalidMaxpTable
|
||||
}
|
||||
}
|
||||
u, err = f.src.u16(buf, f.maxp, 4)
|
||||
u, err := f.src.u16(buf, f.maxp, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
numGlyphs := int(u)
|
||||
numGlyphs = int(u)
|
||||
|
||||
if f.cached.isPostScript {
|
||||
if isPostScript {
|
||||
p := cffParser{
|
||||
src: &f.src,
|
||||
base: int(f.cff.offset),
|
||||
offset: int(f.cff.offset),
|
||||
end: int(f.cff.offset + f.cff.length),
|
||||
}
|
||||
f.cached.locations, err = p.parse()
|
||||
locations, err = p.parse()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
} else {
|
||||
f.cached.locations, err = parseLoca(
|
||||
&f.src, f.loca, f.glyf.offset, f.cached.indexToLocFormat, numGlyphs)
|
||||
locations, err = parseLoca(&f.src, f.loca, f.glyf.offset, indexToLocFormat, numGlyphs)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, 0, nil, err
|
||||
}
|
||||
}
|
||||
if len(f.cached.locations) != numGlyphs+1 {
|
||||
return errInvalidLocationData
|
||||
if len(locations) != numGlyphs+1 {
|
||||
return nil, 0, nil, errInvalidLocationData
|
||||
}
|
||||
return nil
|
||||
|
||||
return buf, numGlyphs, locations, nil
|
||||
}
|
||||
|
||||
// TODO: func (f *Font) GlyphIndex(r rune) (x GlyphIndex, ok bool)
|
||||
// This will require parsing the cmap table.
|
||||
func (f *Font) parsePost(buf []byte, numGlyphs int) (buf1 []byte, postTableVersion uint32, err error) {
|
||||
// https://www.microsoft.com/typography/otspec/post.htm
|
||||
|
||||
const headerSize = 32
|
||||
if f.post.length < headerSize {
|
||||
return nil, 0, errInvalidPostTable
|
||||
}
|
||||
u, err := f.src.u32(buf, f.post, 0)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
switch u {
|
||||
case 0x20000:
|
||||
if f.post.length < headerSize+2+2*uint32(numGlyphs) {
|
||||
return nil, 0, errInvalidPostTable
|
||||
}
|
||||
case 0x30000:
|
||||
// No-op.
|
||||
default:
|
||||
return nil, 0, errUnsupportedPostTable
|
||||
}
|
||||
return buf, u, nil
|
||||
}
|
||||
|
||||
// TODO: API for looking up glyph variants?? For example, some fonts may
|
||||
// provide both slashed and dotted zero glyphs ('0'), or regular and 'old
|
||||
// style' numerals, and users can direct software to choose a variant.
|
||||
|
||||
type glyphIndexFunc func(f *Font, b *Buffer, r rune) (GlyphIndex, error)
|
||||
|
||||
// GlyphIndex returns the glyph index for the given rune.
|
||||
//
|
||||
// It returns (0, nil) if there is no glyph for r.
|
||||
// https://www.microsoft.com/typography/OTSPEC/cmap.htm says that "Character
|
||||
// codes that do not correspond to any glyph in the font should be mapped to
|
||||
// glyph index 0. The glyph at this location must be a special glyph
|
||||
// representing a missing character, commonly known as .notdef."
|
||||
func (f *Font) GlyphIndex(b *Buffer, r rune) (GlyphIndex, error) {
|
||||
return f.cached.glyphIndex(f, b, r)
|
||||
}
|
||||
|
||||
func (f *Font) viewGlyphData(b *Buffer, x GlyphIndex) ([]byte, error) {
|
||||
xx := int(x)
|
||||
@@ -458,15 +752,16 @@ func (f *Font) viewGlyphData(b *Buffer, x GlyphIndex) ([]byte, error) {
|
||||
|
||||
// LoadGlyphOptions are the options to the Font.LoadGlyph method.
|
||||
type LoadGlyphOptions struct {
|
||||
// TODO: scale / transform / hinting.
|
||||
// TODO: transform / hinting.
|
||||
}
|
||||
|
||||
// LoadGlyph returns the vector segments for the x'th glyph.
|
||||
// LoadGlyph returns the vector segments for the x'th glyph. ppem is the number
|
||||
// of pixels in 1 em.
|
||||
//
|
||||
// If b is non-nil, the segments become invalid to use once b is re-used.
|
||||
//
|
||||
// It returns ErrNotFound if the glyph index is out of range.
|
||||
func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, opts *LoadGlyphOptions) ([]Segment, error) {
|
||||
func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, ppem fixed.Int26_6, opts *LoadGlyphOptions) ([]Segment, error) {
|
||||
if b == nil {
|
||||
b = &Buffer{}
|
||||
}
|
||||
@@ -491,11 +786,153 @@ func (f *Font) LoadGlyph(b *Buffer, x GlyphIndex, opts *LoadGlyphOptions) ([]Seg
|
||||
b.segments = segments
|
||||
}
|
||||
|
||||
// TODO: look at opts to scale / transform / hint the Buffer.segments.
|
||||
// Scale the segments. If we want to support hinting, we'll have to push
|
||||
// the scaling computation into the PostScript / TrueType specific glyph
|
||||
// loading code, such as the appendGlyfSegments body, since TrueType
|
||||
// hinting bytecode works on the scaled glyph vectors. For now, though,
|
||||
// it's simpler to scale as a post-processing step.
|
||||
for i := range b.segments {
|
||||
s := &b.segments[i]
|
||||
for j := range s.Args {
|
||||
s.Args[j] = scale(s.Args[j]*ppem, f.cached.unitsPerEm)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: look at opts to transform / hint the Buffer.segments.
|
||||
|
||||
return b.segments, nil
|
||||
}
|
||||
|
||||
// GlyphName returns the name of the x'th glyph.
|
||||
//
|
||||
// Not every font contains glyph names. If not present, GlyphName will return
|
||||
// ("", nil).
|
||||
//
|
||||
// If present, the glyph name, provided by the font, is assumed to follow the
|
||||
// Adobe Glyph List Specification:
|
||||
// https://github.com/adobe-type-tools/agl-specification/blob/master/README.md
|
||||
//
|
||||
// This is also known as the "Adobe Glyph Naming convention", the "Adobe
|
||||
// document [for] Unicode and Glyph Names" or "PostScript glyph names".
|
||||
//
|
||||
// It returns ErrNotFound if the glyph index is out of range.
|
||||
func (f *Font) GlyphName(b *Buffer, x GlyphIndex) (string, error) {
|
||||
if int(x) >= f.NumGlyphs() {
|
||||
return "", ErrNotFound
|
||||
}
|
||||
if f.cached.postTableVersion != 0x20000 {
|
||||
return "", nil
|
||||
}
|
||||
if b == nil {
|
||||
b = &Buffer{}
|
||||
}
|
||||
|
||||
// The wire format for a Version 2 post table is documented at:
|
||||
// https://www.microsoft.com/typography/otspec/post.htm
|
||||
const glyphNameIndexOffset = 34
|
||||
|
||||
buf, err := b.view(&f.src, int(f.post.offset)+glyphNameIndexOffset+2*int(x), 2)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
u := u16(buf)
|
||||
if u < numBuiltInPostNames {
|
||||
i := builtInPostNamesOffsets[u+0]
|
||||
j := builtInPostNamesOffsets[u+1]
|
||||
return builtInPostNamesData[i:j], nil
|
||||
}
|
||||
// https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6post.html
|
||||
// says that "32768 through 65535 are reserved for future use".
|
||||
if u > 32767 {
|
||||
return "", errUnsupportedPostTable
|
||||
}
|
||||
u -= numBuiltInPostNames
|
||||
|
||||
// Iterate through the list of Pascal-formatted strings. A linear scan is
|
||||
// clearly O(u), which isn't great (as the obvious loop, calling
|
||||
// Font.GlyphName, to get all of the glyph names in a font has quadratic
|
||||
// complexity), but the wire format doesn't suggest a better alternative.
|
||||
|
||||
offset := glyphNameIndexOffset + 2*f.NumGlyphs()
|
||||
buf, err = b.view(&f.src, int(f.post.offset)+offset, int(f.post.length)-offset)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
if len(buf) == 0 {
|
||||
return "", errInvalidPostTable
|
||||
}
|
||||
n := 1 + int(buf[0])
|
||||
if len(buf) < n {
|
||||
return "", errInvalidPostTable
|
||||
}
|
||||
if u == 0 {
|
||||
return string(buf[1:n]), nil
|
||||
}
|
||||
buf = buf[n:]
|
||||
u--
|
||||
}
|
||||
}
|
||||
|
||||
// Kern returns the horizontal adjustment for the kerning pair (x0, x1). A
|
||||
// positive kern means to move the glyphs further apart. ppem is the number of
|
||||
// pixels in 1 em.
|
||||
//
|
||||
// It returns ErrNotFound if either glyph index is out of range.
|
||||
func (f *Font) Kern(b *Buffer, x0, x1 GlyphIndex, ppem fixed.Int26_6, h font.Hinting) (fixed.Int26_6, error) {
|
||||
// TODO: how should this work with the GPOS table and CFF fonts?
|
||||
// https://www.microsoft.com/typography/otspec/kern.htm says that
|
||||
// "OpenType™ fonts containing CFF outlines are not supported by the 'kern'
|
||||
// table and must use the 'GPOS' OpenType Layout table."
|
||||
|
||||
if n := f.NumGlyphs(); int(x0) >= n || int(x1) >= n {
|
||||
return 0, ErrNotFound
|
||||
}
|
||||
// Not every font has a kern table. If it doesn't, there's no need to
|
||||
// allocate a Buffer.
|
||||
if f.kern.length == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if b == nil {
|
||||
b = &Buffer{}
|
||||
}
|
||||
|
||||
key := uint32(x0)<<16 | uint32(x1)
|
||||
lo, hi := int32(0), f.cached.kernNumPairs
|
||||
for lo < hi {
|
||||
i := (lo + hi) / 2
|
||||
|
||||
// TODO: this view call inside the inner loop can lead to many small
|
||||
// reads instead of fewer larger reads, which can be expensive. We
|
||||
// should be able to do better, although we don't want to make (one)
|
||||
// arbitrarily large read. Perhaps we should round up reads to 4K or 8K
|
||||
// chunks. For reference, Arial.ttf's kern table is 5472 bytes.
|
||||
// Times_New_Roman.ttf's kern table is 5220 bytes.
|
||||
const entrySize = 6
|
||||
buf, err := b.view(&f.src, int(f.cached.kernOffset+i*entrySize), entrySize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
k := u32(buf)
|
||||
if k < key {
|
||||
lo = i + 1
|
||||
} else if k > key {
|
||||
hi = i
|
||||
} else {
|
||||
kern := fixed.Int26_6(int16(u16(buf[4:])))
|
||||
kern = scale(kern*ppem, f.cached.unitsPerEm)
|
||||
if h == font.HintingFull {
|
||||
// Quantize the fixed.Int26_6 value to the nearest pixel.
|
||||
kern = (kern + 32) &^ 63
|
||||
}
|
||||
return kern, nil
|
||||
}
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// Name returns the name value keyed by the given NameID.
|
||||
//
|
||||
// It returns ErrNotFound if there is no value for that key.
|
||||
@@ -512,14 +949,14 @@ func (f *Font) Name(b *Buffer, id NameID) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
nSubtables := u16(buf[2:])
|
||||
if f.name.length < headerSize+entrySize*uint32(nSubtables) {
|
||||
numSubtables := u16(buf[2:])
|
||||
if f.name.length < headerSize+entrySize*uint32(numSubtables) {
|
||||
return "", errInvalidNameTable
|
||||
}
|
||||
stringOffset := u16(buf[4:])
|
||||
|
||||
seen := false
|
||||
for i, n := 0, int(nSubtables); i < n; i++ {
|
||||
for i, n := 0, int(numSubtables); i < n; i++ {
|
||||
buf, err := b.view(&f.src, int(f.name.offset)+headerSize+entrySize*i, entrySize)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
370
vendor/golang.org/x/image/font/sfnt/sfnt_test.go
сгенерированный
поставляемый
@@ -6,6 +6,7 @@ package sfnt
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@@ -14,52 +15,48 @@ import (
|
||||
"golang.org/x/image/math/fixed"
|
||||
)
|
||||
|
||||
func moveTo(xa, ya int) Segment {
|
||||
func moveTo(xa, ya fixed.Int26_6) Segment {
|
||||
return Segment{
|
||||
Op: SegmentOpMoveTo,
|
||||
Args: [6]fixed.Int26_6{
|
||||
0: fixed.I(xa),
|
||||
1: fixed.I(ya),
|
||||
},
|
||||
Op: SegmentOpMoveTo,
|
||||
Args: [6]fixed.Int26_6{xa, ya},
|
||||
}
|
||||
}
|
||||
|
||||
func lineTo(xa, ya int) Segment {
|
||||
func lineTo(xa, ya fixed.Int26_6) Segment {
|
||||
return Segment{
|
||||
Op: SegmentOpLineTo,
|
||||
Args: [6]fixed.Int26_6{
|
||||
0: fixed.I(xa),
|
||||
1: fixed.I(ya),
|
||||
},
|
||||
Op: SegmentOpLineTo,
|
||||
Args: [6]fixed.Int26_6{xa, ya},
|
||||
}
|
||||
}
|
||||
|
||||
func quadTo(xa, ya, xb, yb int) Segment {
|
||||
func quadTo(xa, ya, xb, yb fixed.Int26_6) Segment {
|
||||
return Segment{
|
||||
Op: SegmentOpQuadTo,
|
||||
Args: [6]fixed.Int26_6{
|
||||
0: fixed.I(xa),
|
||||
1: fixed.I(ya),
|
||||
2: fixed.I(xb),
|
||||
3: fixed.I(yb),
|
||||
},
|
||||
Op: SegmentOpQuadTo,
|
||||
Args: [6]fixed.Int26_6{xa, ya, xb, yb},
|
||||
}
|
||||
}
|
||||
|
||||
func cubeTo(xa, ya, xb, yb, xc, yc int) Segment {
|
||||
func cubeTo(xa, ya, xb, yb, xc, yc fixed.Int26_6) Segment {
|
||||
return Segment{
|
||||
Op: SegmentOpCubeTo,
|
||||
Args: [6]fixed.Int26_6{
|
||||
0: fixed.I(xa),
|
||||
1: fixed.I(ya),
|
||||
2: fixed.I(xb),
|
||||
3: fixed.I(yb),
|
||||
4: fixed.I(xc),
|
||||
5: fixed.I(yc),
|
||||
},
|
||||
Op: SegmentOpCubeTo,
|
||||
Args: [6]fixed.Int26_6{xa, ya, xb, yb, xc, yc},
|
||||
}
|
||||
}
|
||||
|
||||
func checkSegmentsEqual(got, want []Segment) error {
|
||||
if len(got) != len(want) {
|
||||
return fmt.Errorf("got %d elements, want %d\noverall:\ngot %v\nwant %v",
|
||||
len(got), len(want), got, want)
|
||||
}
|
||||
for i, g := range got {
|
||||
if w := want[i]; g != w {
|
||||
return fmt.Errorf("element %d:\ngot %v\nwant %v\noverall:\ngot %v\nwant %v",
|
||||
i, g, w, got, want)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestTrueTypeParse(t *testing.T) {
|
||||
f, err := Parse(goregular.TTF)
|
||||
if err != nil {
|
||||
@@ -88,6 +85,167 @@ func testTrueType(t *testing.T, f *Font) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoRegularGlyphIndex(t *testing.T) {
|
||||
f, err := Parse(goregular.TTF)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse: %v", err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
r rune
|
||||
want GlyphIndex
|
||||
}{
|
||||
// Glyphs that aren't present in Go Regular.
|
||||
{'\u001f', 0}, // U+001F <control>
|
||||
{'\u0200', 0}, // U+0200 LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
|
||||
{'\u2000', 0}, // U+2000 EN QUAD
|
||||
|
||||
// The want values below can be verified by running the ttx tool on
|
||||
// Go-Regular.ttf.
|
||||
//
|
||||
// The actual values are ad hoc, and result from whatever tools the
|
||||
// Bigelow & Holmes type foundry used and the order in which they
|
||||
// crafted the glyphs. They may change over time as newer versions of
|
||||
// the font are released. In practice, though, running this test with
|
||||
// coverage analysis suggests that it covers both the zero and non-zero
|
||||
// cmapEntry16.offset cases for a format-4 cmap table.
|
||||
|
||||
{'\u0020', 3}, // U+0020 SPACE
|
||||
{'\u0021', 4}, // U+0021 EXCLAMATION MARK
|
||||
{'\u0022', 5}, // U+0022 QUOTATION MARK
|
||||
{'\u0023', 6}, // U+0023 NUMBER SIGN
|
||||
{'\u0024', 223}, // U+0024 DOLLAR SIGN
|
||||
{'\u0025', 7}, // U+0025 PERCENT SIGN
|
||||
{'\u0026', 8}, // U+0026 AMPERSAND
|
||||
{'\u0027', 9}, // U+0027 APOSTROPHE
|
||||
|
||||
{'\u03bd', 423}, // U+03BD GREEK SMALL LETTER NU
|
||||
{'\u03be', 424}, // U+03BE GREEK SMALL LETTER XI
|
||||
{'\u03bf', 438}, // U+03BF GREEK SMALL LETTER OMICRON
|
||||
{'\u03c0', 208}, // U+03C0 GREEK SMALL LETTER PI
|
||||
{'\u03c1', 425}, // U+03C1 GREEK SMALL LETTER RHO
|
||||
{'\u03c2', 426}, // U+03C2 GREEK SMALL LETTER FINAL SIGMA
|
||||
}
|
||||
|
||||
var b Buffer
|
||||
for _, tc := range testCases {
|
||||
got, err := f.GlyphIndex(&b, tc.r)
|
||||
if err != nil {
|
||||
t.Errorf("r=%q: %v", tc.r, err)
|
||||
continue
|
||||
}
|
||||
if got != tc.want {
|
||||
t.Errorf("r=%q: got %d, want %d", tc.r, got, tc.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGlyphIndex(t *testing.T) {
|
||||
data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/cmapTest.ttf"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, format := range []int{-1, 0, 4, 12} {
|
||||
testGlyphIndex(t, data, format)
|
||||
}
|
||||
}
|
||||
|
||||
func testGlyphIndex(t *testing.T, data []byte, cmapFormat int) {
|
||||
if cmapFormat >= 0 {
|
||||
originalSupportedCmapFormat := supportedCmapFormat
|
||||
defer func() {
|
||||
supportedCmapFormat = originalSupportedCmapFormat
|
||||
}()
|
||||
supportedCmapFormat = func(format, pid, psid uint16) bool {
|
||||
return int(format) == cmapFormat && originalSupportedCmapFormat(format, pid, psid)
|
||||
}
|
||||
}
|
||||
|
||||
f, err := Parse(data)
|
||||
if err != nil {
|
||||
t.Errorf("cmapFormat=%d: %v", cmapFormat, err)
|
||||
return
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
r rune
|
||||
want GlyphIndex
|
||||
}{
|
||||
// Glyphs that aren't present in cmapTest.ttf.
|
||||
{'?', 0},
|
||||
{'\ufffd', 0},
|
||||
{'\U0001f4a9', 0},
|
||||
|
||||
// For a .TTF file, FontForge maps:
|
||||
// - ".notdef" to glyph index 0.
|
||||
// - ".null" to glyph index 1.
|
||||
// - "nonmarkingreturn" to glyph index 2.
|
||||
|
||||
{'/', 0},
|
||||
{'0', 3},
|
||||
{'1', 4},
|
||||
{'2', 5},
|
||||
{'3', 0},
|
||||
|
||||
{'@', 0},
|
||||
{'A', 6},
|
||||
{'B', 7},
|
||||
{'C', 0},
|
||||
|
||||
{'`', 0},
|
||||
{'a', 8},
|
||||
{'b', 0},
|
||||
|
||||
// Of the remaining runes, only U+00FF LATIN SMALL LETTER Y WITH
|
||||
// DIAERESIS is in both the Mac Roman encoding and the cmapTest.ttf
|
||||
// font file.
|
||||
{'\u00fe', 0},
|
||||
{'\u00ff', 9},
|
||||
{'\u0100', 10},
|
||||
{'\u0101', 11},
|
||||
{'\u0102', 0},
|
||||
|
||||
{'\u4e2c', 0},
|
||||
{'\u4e2d', 12},
|
||||
{'\u4e2e', 0},
|
||||
|
||||
{'\U0001f0a0', 0},
|
||||
{'\U0001f0a1', 13},
|
||||
{'\U0001f0a2', 0},
|
||||
|
||||
{'\U0001f0b0', 0},
|
||||
{'\U0001f0b1', 14},
|
||||
{'\U0001f0b2', 15},
|
||||
{'\U0001f0b3', 0},
|
||||
}
|
||||
|
||||
var b Buffer
|
||||
for _, tc := range testCases {
|
||||
want := tc.want
|
||||
switch {
|
||||
case cmapFormat == 0 && tc.r > '\u007f' && tc.r != '\u00ff':
|
||||
// cmap format 0, with the Macintosh Roman encoding, can only
|
||||
// represent a limited set of non-ASCII runes, e.g. U+00FF.
|
||||
want = 0
|
||||
case cmapFormat == 4 && tc.r > '\uffff':
|
||||
// cmap format 4 only supports the Basic Multilingual Plane (BMP).
|
||||
want = 0
|
||||
}
|
||||
|
||||
got, err := f.GlyphIndex(&b, tc.r)
|
||||
if err != nil {
|
||||
t.Errorf("cmapFormat=%d, r=%q: %v", cmapFormat, tc.r, err)
|
||||
continue
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("cmapFormat=%d, r=%q: got %d, want %d", cmapFormat, tc.r, got, want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostScriptSegments(t *testing.T) {
|
||||
// wants' vectors correspond 1-to-1 to what's in the CFFTest.sfd file,
|
||||
// although OpenType/CFF and FontForge's SFD have reversed orders.
|
||||
@@ -226,40 +384,32 @@ func TestTrueTypeSegments(t *testing.T) {
|
||||
}
|
||||
|
||||
func testSegments(t *testing.T, filename string, wants [][]Segment) {
|
||||
data, err := ioutil.ReadFile(filepath.Join("..", "testdata", filename))
|
||||
data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/" + filename))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("ReadFile: %v", err)
|
||||
}
|
||||
f, err := Parse(data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
t.Fatalf("Parse: %v", err)
|
||||
}
|
||||
ppem := fixed.Int26_6(f.UnitsPerEm())
|
||||
|
||||
if ng := f.NumGlyphs(); ng != len(wants) {
|
||||
t.Fatalf("NumGlyphs: got %d, want %d", ng, len(wants))
|
||||
}
|
||||
var b Buffer
|
||||
loop:
|
||||
for i, want := range wants {
|
||||
got, err := f.LoadGlyph(&b, GlyphIndex(i), nil)
|
||||
got, err := f.LoadGlyph(&b, GlyphIndex(i), ppem, nil)
|
||||
if err != nil {
|
||||
t.Errorf("i=%d: LoadGlyph: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if len(got) != len(want) {
|
||||
t.Errorf("i=%d: got %d elements, want %d\noverall:\ngot %v\nwant %v",
|
||||
i, len(got), len(want), got, want)
|
||||
if err := checkSegmentsEqual(got, want); err != nil {
|
||||
t.Errorf("i=%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
for j, g := range got {
|
||||
if w := want[j]; g != w {
|
||||
t.Errorf("i=%d: element %d:\ngot %v\nwant %v\noverall:\ngot %v\nwant %v",
|
||||
i, j, g, w, got, want)
|
||||
continue loop
|
||||
}
|
||||
}
|
||||
}
|
||||
if _, err := f.LoadGlyph(nil, 0xffff, nil); err != ErrNotFound {
|
||||
if _, err := f.LoadGlyph(nil, 0xffff, ppem, nil); err != ErrNotFound {
|
||||
t.Errorf("LoadGlyph(..., 0xffff, ...):\ngot %v\nwant %v", err, ErrNotFound)
|
||||
}
|
||||
|
||||
@@ -270,3 +420,131 @@ loop:
|
||||
t.Errorf("Name:\ngot %q\nwant %q", name, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPPEM(t *testing.T) {
|
||||
data, err := ioutil.ReadFile(filepath.FromSlash("../testdata/glyfTest.ttf"))
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile: %v", err)
|
||||
}
|
||||
f, err := Parse(data)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse: %v", err)
|
||||
}
|
||||
var b Buffer
|
||||
x, err := f.GlyphIndex(&b, '1')
|
||||
if err != nil {
|
||||
t.Fatalf("GlyphIndex: %v", err)
|
||||
}
|
||||
if x == 0 {
|
||||
t.Fatalf("GlyphIndex: no glyph index found for the rune '1'")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
ppem fixed.Int26_6
|
||||
want []Segment
|
||||
}{{
|
||||
ppem: fixed.Int26_6(12 << 6),
|
||||
want: []Segment{
|
||||
moveTo(77, 0),
|
||||
lineTo(77, 614),
|
||||
lineTo(230, 614),
|
||||
lineTo(230, 0),
|
||||
lineTo(77, 0),
|
||||
},
|
||||
}, {
|
||||
ppem: fixed.Int26_6(2048),
|
||||
want: []Segment{
|
||||
moveTo(205, 0),
|
||||
lineTo(205, 1638),
|
||||
lineTo(614, 1638),
|
||||
lineTo(614, 0),
|
||||
lineTo(205, 0),
|
||||
},
|
||||
}}
|
||||
|
||||
for i, tc := range testCases {
|
||||
got, err := f.LoadGlyph(&b, x, tc.ppem, nil)
|
||||
if err != nil {
|
||||
t.Errorf("i=%d: LoadGlyph: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if err := checkSegmentsEqual(got, tc.want); err != nil {
|
||||
t.Errorf("i=%d: %v", i, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGlyphName(t *testing.T) {
|
||||
f, err := Parse(goregular.TTF)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse: %v", err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
r rune
|
||||
want string
|
||||
}{
|
||||
{'\x00', "NULL"},
|
||||
{'!', "exclam"},
|
||||
{'A', "A"},
|
||||
{'{', "braceleft"},
|
||||
{'\u00c4', "Adieresis"}, // U+00C4 LATIN CAPITAL LETTER A WITH DIAERESIS
|
||||
{'\u2020', "dagger"}, // U+2020 DAGGER
|
||||
{'\u2660', "spade"}, // U+2660 BLACK SPADE SUIT
|
||||
{'\uf800', "gopher"}, // U+F800 <Private Use>
|
||||
{'\ufffe', ".notdef"}, // Not in the Go Regular font, so GlyphIndex returns (0, nil).
|
||||
}
|
||||
|
||||
var b Buffer
|
||||
for _, tc := range testCases {
|
||||
x, err := f.GlyphIndex(&b, tc.r)
|
||||
if err != nil {
|
||||
t.Errorf("r=%q: GlyphIndex: %v", tc.r, err)
|
||||
continue
|
||||
}
|
||||
got, err := f.GlyphName(&b, x)
|
||||
if err != nil {
|
||||
t.Errorf("r=%q: GlyphName: %v", tc.r, err)
|
||||
continue
|
||||
}
|
||||
if got != tc.want {
|
||||
t.Errorf("r=%q: got %q, want %q", tc.r, got, tc.want)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltInPostNames(t *testing.T) {
|
||||
testCases := []struct {
|
||||
x GlyphIndex
|
||||
want string
|
||||
}{
|
||||
{0, ".notdef"},
|
||||
{1, ".null"},
|
||||
{2, "nonmarkingreturn"},
|
||||
{13, "asterisk"},
|
||||
{36, "A"},
|
||||
{93, "z"},
|
||||
{123, "ocircumflex"},
|
||||
{202, "Edieresis"},
|
||||
{255, "Ccaron"},
|
||||
{256, "ccaron"},
|
||||
{257, "dcroat"},
|
||||
{258, ""},
|
||||
{999, ""},
|
||||
{0xffff, ""},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
if tc.x >= numBuiltInPostNames {
|
||||
continue
|
||||
}
|
||||
i := builtInPostNamesOffsets[tc.x+0]
|
||||
j := builtInPostNamesOffsets[tc.x+1]
|
||||
got := builtInPostNamesData[i:j]
|
||||
if got != tc.want {
|
||||
t.Errorf("x=%d: got %q, want %q", tc.x, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
29
vendor/golang.org/x/image/font/sfnt/truetype.go
сгенерированный
поставляемый
@@ -113,6 +113,11 @@ func appendGlyfSegments(dst []Segment, data []byte) ([]Segment, error) {
|
||||
return nil, errInvalidGlyphData
|
||||
}
|
||||
|
||||
// TODO: support compound glyphs.
|
||||
if numContours < 0 {
|
||||
return nil, errUnsupportedCompoundGlyph
|
||||
}
|
||||
|
||||
// Skip the hinting instructions.
|
||||
index += 2
|
||||
if index > len(data) {
|
||||
@@ -124,19 +129,14 @@ func appendGlyfSegments(dst []Segment, data []byte) ([]Segment, error) {
|
||||
return nil, errInvalidGlyphData
|
||||
}
|
||||
|
||||
// TODO: support compound glyphs.
|
||||
if numContours < 0 {
|
||||
return nil, errUnsupportedCompoundGlyph
|
||||
}
|
||||
|
||||
// For simple (non-compound) glyphs, the remainder of the glyf data
|
||||
// consists of (flags, x, y) points: the Bézier curve segments. These are
|
||||
// stored in columns (all the flags first, then all the x co-ordinates,
|
||||
// then all the y co-ordinates), not rows, as it compresses better.
|
||||
// stored in columns (all the flags first, then all the x coordinates, then
|
||||
// all the y coordinates), not rows, as it compresses better.
|
||||
//
|
||||
// Decoding those points in row order involves two passes. The first pass
|
||||
// determines the indexes (relative to the data slice) of where the flags,
|
||||
// the x co-ordinates and the y co-ordinates each start.
|
||||
// the x coordinates and the y coordinates each start.
|
||||
flagIndex := int32(index)
|
||||
xIndex, yIndex, ok := findXYIndexes(data, index, numPoints)
|
||||
if !ok {
|
||||
@@ -357,9 +357,18 @@ func (g *glyfIter) nextSegment() (ok bool) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Convert the tuple (g.x, g.y) to a fixed.Point26_6, since the latter
|
||||
// is what's held in a Segment. The input (g.x, g.y) is a pair of int16
|
||||
// values, measured in font units, since that is what the underlying
|
||||
// format provides. The output is a pair of fixed.Int26_6 values. A
|
||||
// fixed.Int26_6 usually represents a 26.6 fixed number of pixels, but
|
||||
// this here is just a straight numerical conversion, with no scaling
|
||||
// factor. A later step scales the Segment.Args values by such a factor
|
||||
// to convert e.g. 1792 font units to 10.5 pixels at 2048 font units
|
||||
// per em and 12 ppem (pixels per em).
|
||||
p := fixed.Point26_6{
|
||||
X: fixed.Int26_6(g.x) << 6,
|
||||
Y: fixed.Int26_6(g.y) << 6,
|
||||
X: fixed.Int26_6(g.x),
|
||||
Y: fixed.Int26_6(g.y),
|
||||
}
|
||||
|
||||
if !g.firstOnCurveValid {
|
||||
|
||||
265
vendor/golang.org/x/image/font/testdata/cmapTest.sfd
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,265 @@
|
||||
SplineFontDB: 3.0
|
||||
FontName: cmapTest
|
||||
FullName: cmapTest
|
||||
FamilyName: cmapTest
|
||||
Weight: Regular
|
||||
Copyright: Copyright 2016 The Go Authors. All rights reserved.\nUse of this font is governed by a BSD-style license that can be found at https://golang.org/LICENSE.
|
||||
Version: 001.000
|
||||
ItalicAngle: -11.25
|
||||
UnderlinePosition: -204
|
||||
UnderlineWidth: 102
|
||||
Ascent: 1638
|
||||
Descent: 410
|
||||
LayerCount: 2
|
||||
Layer: 0 1 "Back" 1
|
||||
Layer: 1 1 "Fore" 0
|
||||
XUID: [1021 367 888937226 7862908]
|
||||
FSType: 8
|
||||
OS2Version: 0
|
||||
OS2_WeightWidthSlopeOnly: 0
|
||||
OS2_UseTypoMetrics: 1
|
||||
CreationTime: 1484386143
|
||||
ModificationTime: 1486021330
|
||||
PfmFamily: 17
|
||||
TTFWeight: 400
|
||||
TTFWidth: 5
|
||||
LineGap: 184
|
||||
VLineGap: 0
|
||||
OS2TypoAscent: 0
|
||||
OS2TypoAOffset: 1
|
||||
OS2TypoDescent: 0
|
||||
OS2TypoDOffset: 1
|
||||
OS2TypoLinegap: 184
|
||||
OS2WinAscent: 0
|
||||
OS2WinAOffset: 1
|
||||
OS2WinDescent: 0
|
||||
OS2WinDOffset: 1
|
||||
HheadAscent: 0
|
||||
HheadAOffset: 1
|
||||
HheadDescent: 0
|
||||
HheadDOffset: 1
|
||||
OS2Vendor: 'PfEd'
|
||||
MarkAttachClasses: 1
|
||||
DEI: 91125
|
||||
LangName: 1033
|
||||
Encoding: UnicodeFull
|
||||
UnicodeInterp: none
|
||||
NameList: Adobe Glyph List
|
||||
DisplaySize: -24
|
||||
AntiAlias: 1
|
||||
FitToEm: 1
|
||||
WinInfo: 126976 32 23
|
||||
BeginPrivate: 0
|
||||
EndPrivate
|
||||
TeXData: 1 0 0 346030 173015 115343 0 -1048576 115343 783286 444596 497025 792723 393216 433062 380633 303038 157286 324010 404750 52429 2506097 1059062 262144
|
||||
BeginChars: 1114112 13
|
||||
|
||||
StartChar: zero
|
||||
Encoding: 48 48 0
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: one
|
||||
Encoding: 49 49 1
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: two
|
||||
Encoding: 50 50 2
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: A
|
||||
Encoding: 65 65 3
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: uni4E2D
|
||||
Encoding: 20013 20013 4
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: u1F0A1
|
||||
Encoding: 127137 127137 5
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: ydieresis
|
||||
Encoding: 255 255 6
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: Amacron
|
||||
Encoding: 256 256 7
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: amacron
|
||||
Encoding: 257 257 8
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: B
|
||||
Encoding: 66 66 9
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: a
|
||||
Encoding: 97 97 10
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: u1F0B1
|
||||
Encoding: 127153 127153 11
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
|
||||
StartChar: u1F0B2
|
||||
Encoding: 127154 127154 12
|
||||
Width: 800
|
||||
VWidth: 0
|
||||
Flags: W
|
||||
LayerCount: 2
|
||||
Fore
|
||||
SplineSet
|
||||
0 0 m 29,0,-1
|
||||
400 800 l 25,1,-1
|
||||
800 0 l 25,2,-1
|
||||
0 0 l 29,0,-1
|
||||
EndSplineSet
|
||||
Validated: 1
|
||||
EndChar
|
||||
EndChars
|
||||
EndSplineFont
|
||||
Двоичные данные
vendor/golang.org/x/image/font/testdata/cmapTest.ttf
сгенерированный
поставляемый
Обычный файл
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-down-ab.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 21 KiB После Ширина: | Высота: | Размер: 21 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-down-bl.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 18 KiB После Ширина: | Высота: | Размер: 18 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-down-cr.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 19 KiB После Ширина: | Высота: | Размер: 19 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-down-nn.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 21 KiB После Ширина: | Высота: | Размер: 21 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-rotate-ab.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 7.5 KiB После Ширина: | Высота: | Размер: 7.2 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-rotate-bl.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 7.5 KiB После Ширина: | Высота: | Размер: 7.2 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-rotate-cr.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 7.6 KiB После Ширина: | Высота: | Размер: 7.4 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-rotate-nn.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 4.8 KiB После Ширина: | Высота: | Размер: 5.0 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-up-ab.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 9.4 KiB После Ширина: | Высота: | Размер: 9.2 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-up-bl.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 9.4 KiB После Ширина: | Высота: | Размер: 9.2 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-up-cr.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 11 KiB После Ширина: | Высота: | Размер: 10 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/go-turns-two-up-nn.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 1.3 KiB После Ширина: | Высота: | Размер: 1.3 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/tux-rotate-ab.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 3.2 KiB После Ширина: | Высота: | Размер: 3.3 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/tux-rotate-bl.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 3.7 KiB После Ширина: | Высота: | Размер: 3.7 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/tux-rotate-cr.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 3.7 KiB После Ширина: | Высота: | Размер: 3.8 KiB |
Двоичные данные
vendor/golang.org/x/image/testdata/tux-rotate-nn.png
сгенерированный
поставляемый
|
До Ширина: | Высота: | Размер: 3.0 KiB После Ширина: | Высота: | Размер: 3.1 KiB |
7
vendor/golang.org/x/net/bpf/vm_bpf_test.go
сгенерированный
поставляемый
@@ -33,7 +33,7 @@ func canUseOSVM() bool {
|
||||
}
|
||||
|
||||
// All BPF tests against both the Go VM and OS VM are assumed to
|
||||
// be used with a UDP socket. As a result, the entire contents
|
||||
// be used with a UDP socket. As a result, the entire contents
|
||||
// of a UDP datagram is sent through the BPF program, but only
|
||||
// the body after the UDP header will ever be returned in output.
|
||||
|
||||
@@ -85,7 +85,7 @@ func (mvm *multiVirtualMachine) Run(in []byte) (int, error) {
|
||||
}
|
||||
|
||||
// All tests have a UDP header as part of input, because the OS VM
|
||||
// packets always will. For the Go VM, this output is trimmed before
|
||||
// packets always will. For the Go VM, this output is trimmed before
|
||||
// being sent back to tests.
|
||||
goOut, goErr := mvm.goVM.Run(in)
|
||||
if goOut >= udpHeaderLen {
|
||||
@@ -149,6 +149,9 @@ func testOSVM(t *testing.T, filter []bpf.Instruction) (virtualMachine, func()) {
|
||||
|
||||
p := ipv4.NewPacketConn(l)
|
||||
if err = p.SetBPF(prog); err != nil {
|
||||
if err.Error() == "operation not supported" { // TODO: gross. remove once 19051 fixed.
|
||||
t.Skip("Skipping until Issue 19051 is fixed.")
|
||||
}
|
||||
t.Fatalf("failed to attach BPF program to listener: %v", err)
|
||||
}
|
||||
|
||||
|
||||
30
vendor/golang.org/x/net/context/context.go
сгенерированный
поставляемый
@@ -7,7 +7,7 @@
|
||||
// and between processes.
|
||||
//
|
||||
// Incoming requests to a server should create a Context, and outgoing calls to
|
||||
// servers should accept a Context. The chain of function calls between must
|
||||
// servers should accept a Context. The chain of function calls between must
|
||||
// propagate the Context, optionally replacing it with a modified copy created
|
||||
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
||||
//
|
||||
@@ -16,14 +16,14 @@
|
||||
// propagation:
|
||||
//
|
||||
// Do not store Contexts inside a struct type; instead, pass a Context
|
||||
// explicitly to each function that needs it. The Context should be the first
|
||||
// explicitly to each function that needs it. The Context should be the first
|
||||
// parameter, typically named ctx:
|
||||
//
|
||||
// func DoSomething(ctx context.Context, arg Arg) error {
|
||||
// // ... use ctx ...
|
||||
// }
|
||||
//
|
||||
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||
// if you are unsure about which Context to use.
|
||||
//
|
||||
// Use context Values only for request-scoped data that transits processes and
|
||||
@@ -44,13 +44,13 @@ import "time"
|
||||
// Context's methods may be called by multiple goroutines simultaneously.
|
||||
type Context interface {
|
||||
// Deadline returns the time when work done on behalf of this context
|
||||
// should be canceled. Deadline returns ok==false when no deadline is
|
||||
// set. Successive calls to Deadline return the same results.
|
||||
// should be canceled. Deadline returns ok==false when no deadline is
|
||||
// set. Successive calls to Deadline return the same results.
|
||||
Deadline() (deadline time.Time, ok bool)
|
||||
|
||||
// Done returns a channel that's closed when work done on behalf of this
|
||||
// context should be canceled. Done may return nil if this context can
|
||||
// never be canceled. Successive calls to Done return the same value.
|
||||
// context should be canceled. Done may return nil if this context can
|
||||
// never be canceled. Successive calls to Done return the same value.
|
||||
//
|
||||
// WithCancel arranges for Done to be closed when cancel is called;
|
||||
// WithDeadline arranges for Done to be closed when the deadline
|
||||
@@ -79,24 +79,24 @@ type Context interface {
|
||||
// a Done channel for cancelation.
|
||||
Done() <-chan struct{}
|
||||
|
||||
// Err returns a non-nil error value after Done is closed. Err returns
|
||||
// Err returns a non-nil error value after Done is closed. Err returns
|
||||
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||
// context's deadline passed. No other values for Err are defined.
|
||||
// context's deadline passed. No other values for Err are defined.
|
||||
// After Done is closed, successive calls to Err return the same value.
|
||||
Err() error
|
||||
|
||||
// Value returns the value associated with this context for key, or nil
|
||||
// if no value is associated with key. Successive calls to Value with
|
||||
// if no value is associated with key. Successive calls to Value with
|
||||
// the same key returns the same result.
|
||||
//
|
||||
// Use context values only for request-scoped data that transits
|
||||
// processes and API boundaries, not for passing optional parameters to
|
||||
// functions.
|
||||
//
|
||||
// A key identifies a specific value in a Context. Functions that wish
|
||||
// A key identifies a specific value in a Context. Functions that wish
|
||||
// to store values in Context typically allocate a key in a global
|
||||
// variable then use that key as the argument to context.WithValue and
|
||||
// Context.Value. A key can be any type that supports equality;
|
||||
// Context.Value. A key can be any type that supports equality;
|
||||
// packages should define keys as an unexported type to avoid
|
||||
// collisions.
|
||||
//
|
||||
@@ -115,7 +115,7 @@ type Context interface {
|
||||
// // This prevents collisions with keys defined in other packages.
|
||||
// type key int
|
||||
//
|
||||
// // userKey is the key for user.User values in Contexts. It is
|
||||
// // userKey is the key for user.User values in Contexts. It is
|
||||
// // unexported; clients use user.NewContext and user.FromContext
|
||||
// // instead of using this key directly.
|
||||
// var userKey key = 0
|
||||
@@ -134,14 +134,14 @@ type Context interface {
|
||||
}
|
||||
|
||||
// Background returns a non-nil, empty Context. It is never canceled, has no
|
||||
// values, and has no deadline. It is typically used by the main function,
|
||||
// values, and has no deadline. It is typically used by the main function,
|
||||
// initialization, and tests, and as the top-level Context for incoming
|
||||
// requests.
|
||||
func Background() Context {
|
||||
return background
|
||||
}
|
||||
|
||||
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||
// it's unclear which Context to use or it is not yet available (because the
|
||||
// surrounding function has not yet been extended to accept a Context
|
||||
// parameter). TODO is recognized by static analysis tools that determine
|
||||
|
||||
1
vendor/golang.org/x/net/context/ctxhttp/ctxhttp_17_test.go
сгенерированный
поставляемый
@@ -19,6 +19,7 @@ func TestGo17Context(t *testing.T) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
io.WriteString(w, "ok")
|
||||
}))
|
||||
defer ts.Close()
|
||||
ctx := context.Background()
|
||||
resp, err := Get(ctx, http.DefaultClient, ts.URL)
|
||||
if resp == nil || err != nil {
|
||||
|
||||
4
vendor/golang.org/x/net/context/go17.go
сгенерированный
поставляемый
@@ -35,8 +35,8 @@ func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||
}
|
||||
|
||||
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||
// context's Done channel is closed when the deadline expires, when the returned
|
||||
// cancel function is called, or when the parent context's Done channel is
|
||||
// closed, whichever happens first.
|
||||
|
||||
18
vendor/golang.org/x/net/context/pre_go17.go
сгенерированный
поставляемый
@@ -13,7 +13,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||
// struct{}, since vars of this type must have distinct addresses.
|
||||
type emptyCtx int
|
||||
|
||||
@@ -104,7 +104,7 @@ func propagateCancel(parent Context, child canceler) {
|
||||
}
|
||||
|
||||
// parentCancelCtx follows a chain of parent references until it finds a
|
||||
// *cancelCtx. This function understands how each of the concrete types in this
|
||||
// *cancelCtx. This function understands how each of the concrete types in this
|
||||
// package represents its parent.
|
||||
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||
for {
|
||||
@@ -134,14 +134,14 @@ func removeChild(parent Context, child canceler) {
|
||||
p.mu.Unlock()
|
||||
}
|
||||
|
||||
// A canceler is a context type that can be canceled directly. The
|
||||
// A canceler is a context type that can be canceled directly. The
|
||||
// implementations are *cancelCtx and *timerCtx.
|
||||
type canceler interface {
|
||||
cancel(removeFromParent bool, err error)
|
||||
Done() <-chan struct{}
|
||||
}
|
||||
|
||||
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||
// that implement canceler.
|
||||
type cancelCtx struct {
|
||||
Context
|
||||
@@ -193,8 +193,8 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||
}
|
||||
|
||||
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||
// context's Done channel is closed when the deadline expires, when the returned
|
||||
// cancel function is called, or when the parent context's Done channel is
|
||||
// closed, whichever happens first.
|
||||
@@ -226,8 +226,8 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||
return c, func() { c.cancel(true, Canceled) }
|
||||
}
|
||||
|
||||
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||
// implement Done and Err. It implements cancel by stopping its timer then
|
||||
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||
// implement Done and Err. It implements cancel by stopping its timer then
|
||||
// delegating to cancelCtx.cancel.
|
||||
type timerCtx struct {
|
||||
*cancelCtx
|
||||
@@ -281,7 +281,7 @@ func WithValue(parent Context, key interface{}, val interface{}) Context {
|
||||
return &valueCtx{parent, key, val}
|
||||
}
|
||||
|
||||
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||
// delegates all other calls to the embedded Context.
|
||||
type valueCtx struct {
|
||||
Context
|
||||
|
||||
1418
vendor/golang.org/x/net/dns/dnsmessage/message.go
сгенерированный
поставляемый
Обычный файл
575
vendor/golang.org/x/net/dns/dnsmessage/message_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,575 @@
|
||||
// Copyright 2009 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 dnsmessage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func (m *Message) String() string {
|
||||
s := fmt.Sprintf("Message: %#v\n", &m.Header)
|
||||
if len(m.Questions) > 0 {
|
||||
s += "-- Questions\n"
|
||||
for _, q := range m.Questions {
|
||||
s += fmt.Sprintf("%#v\n", q)
|
||||
}
|
||||
}
|
||||
if len(m.Answers) > 0 {
|
||||
s += "-- Answers\n"
|
||||
for _, a := range m.Answers {
|
||||
s += fmt.Sprintf("%#v\n", a)
|
||||
}
|
||||
}
|
||||
if len(m.Authorities) > 0 {
|
||||
s += "-- Authorities\n"
|
||||
for _, ns := range m.Authorities {
|
||||
s += fmt.Sprintf("%#v\n", ns)
|
||||
}
|
||||
}
|
||||
if len(m.Additionals) > 0 {
|
||||
s += "-- Additionals\n"
|
||||
for _, e := range m.Additionals {
|
||||
s += fmt.Sprintf("%#v\n", e)
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func TestQuestionPackUnpack(t *testing.T) {
|
||||
want := Question{
|
||||
Name: ".",
|
||||
Type: TypeA,
|
||||
Class: ClassINET,
|
||||
}
|
||||
buf, err := want.pack(make([]byte, 1, 50), map[string]int{})
|
||||
if err != nil {
|
||||
t.Fatal("Packing failed:", err)
|
||||
}
|
||||
var p Parser
|
||||
p.msg = buf
|
||||
p.header.questions = 1
|
||||
p.section = sectionQuestions
|
||||
p.off = 1
|
||||
got, err := p.Question()
|
||||
if err != nil {
|
||||
t.Fatalf("Unpacking failed: %v\n%s", err, string(buf[1:]))
|
||||
}
|
||||
if p.off != len(buf) {
|
||||
t.Errorf("Unpacked different amount than packed: got n = %d, want = %d", p.off, len(buf))
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Got = %+v, want = %+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamePackUnpack(t *testing.T) {
|
||||
tests := []struct {
|
||||
in string
|
||||
want string
|
||||
err error
|
||||
}{
|
||||
{"", ".", nil},
|
||||
{".", ".", nil},
|
||||
{"google..com", "", errZeroSegLen},
|
||||
{"google.com", "google.com.", nil},
|
||||
{"google..com.", "", errZeroSegLen},
|
||||
{"google.com.", "google.com.", nil},
|
||||
{".google.com.", "", errZeroSegLen},
|
||||
{"www..google.com.", "", errZeroSegLen},
|
||||
{"www.google.com.", "www.google.com.", nil},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
buf, err := packName(make([]byte, 0, 30), test.in, map[string]int{})
|
||||
if err != test.err {
|
||||
t.Errorf("Packing of %s: got err = %v, want err = %v", test.in, err, test.err)
|
||||
continue
|
||||
}
|
||||
if test.err != nil {
|
||||
continue
|
||||
}
|
||||
got, n, err := unpackName(buf, 0)
|
||||
if err != nil {
|
||||
t.Errorf("Unpacking for %s failed: %v", test.in, err)
|
||||
continue
|
||||
}
|
||||
if n != len(buf) {
|
||||
t.Errorf(
|
||||
"Unpacked different amount than packed for %s: got n = %d, want = %d",
|
||||
test.in,
|
||||
n,
|
||||
len(buf),
|
||||
)
|
||||
}
|
||||
if got != test.want {
|
||||
t.Errorf("Unpacking packing of %s: got = %s, want = %s", test.in, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDNSPackUnpack(t *testing.T) {
|
||||
wants := []Message{
|
||||
{
|
||||
Questions: []Question{
|
||||
{
|
||||
Name: ".",
|
||||
Type: TypeAAAA,
|
||||
Class: ClassINET,
|
||||
},
|
||||
},
|
||||
Answers: []Resource{},
|
||||
Authorities: []Resource{},
|
||||
Additionals: []Resource{},
|
||||
},
|
||||
largeTestMsg(),
|
||||
}
|
||||
for i, want := range wants {
|
||||
b, err := want.Pack()
|
||||
if err != nil {
|
||||
t.Fatalf("%d: packing failed: %v", i, err)
|
||||
}
|
||||
var got Message
|
||||
err = got.Unpack(b)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: unpacking failed: %v", i, err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("%d: got = %+v, want = %+v", i, &got, &want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSkipAll(t *testing.T) {
|
||||
msg := largeTestMsg()
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
t.Fatal("Packing large test message:", err)
|
||||
}
|
||||
var p Parser
|
||||
if _, err := p.Start(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
f func() error
|
||||
}{
|
||||
{"SkipAllQuestions", p.SkipAllQuestions},
|
||||
{"SkipAllAnswers", p.SkipAllAnswers},
|
||||
{"SkipAllAuthorities", p.SkipAllAuthorities},
|
||||
{"SkipAllAdditionals", p.SkipAllAdditionals},
|
||||
}
|
||||
for _, test := range tests {
|
||||
for i := 1; i <= 3; i++ {
|
||||
if err := test.f(); err != nil {
|
||||
t.Errorf("Call #%d to %s(): %v", i, test.name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSkipNotStarted(t *testing.T) {
|
||||
var p Parser
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
f func() error
|
||||
}{
|
||||
{"SkipAllQuestions", p.SkipAllQuestions},
|
||||
{"SkipAllAnswers", p.SkipAllAnswers},
|
||||
{"SkipAllAuthorities", p.SkipAllAuthorities},
|
||||
{"SkipAllAdditionals", p.SkipAllAdditionals},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if err := test.f(); err != ErrNotStarted {
|
||||
t.Errorf("Got %s() = %v, want = %v", test.name, err, ErrNotStarted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTooManyRecords(t *testing.T) {
|
||||
const recs = int(^uint16(0)) + 1
|
||||
tests := []struct {
|
||||
name string
|
||||
msg Message
|
||||
want error
|
||||
}{
|
||||
{
|
||||
"Questions",
|
||||
Message{
|
||||
Questions: make([]Question, recs),
|
||||
},
|
||||
errTooManyQuestions,
|
||||
},
|
||||
{
|
||||
"Answers",
|
||||
Message{
|
||||
Answers: make([]Resource, recs),
|
||||
},
|
||||
errTooManyAnswers,
|
||||
},
|
||||
{
|
||||
"Authorities",
|
||||
Message{
|
||||
Authorities: make([]Resource, recs),
|
||||
},
|
||||
errTooManyAuthorities,
|
||||
},
|
||||
{
|
||||
"Additionals",
|
||||
Message{
|
||||
Additionals: make([]Resource, recs),
|
||||
},
|
||||
errTooManyAdditionals,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
if _, got := test.msg.Pack(); got != test.want {
|
||||
t.Errorf("Packing %d %s: got = %v, want = %v", recs, test.name, got, test.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVeryLongTxt(t *testing.T) {
|
||||
want := &TXTResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeTXT,
|
||||
Class: ClassINET,
|
||||
},
|
||||
Txt: loremIpsum,
|
||||
}
|
||||
buf, err := packResource(make([]byte, 0, 8000), want, map[string]int{})
|
||||
if err != nil {
|
||||
t.Fatal("Packing failed:", err)
|
||||
}
|
||||
var hdr ResourceHeader
|
||||
off, err := hdr.unpack(buf, 0)
|
||||
if err != nil {
|
||||
t.Fatal("Unpacking ResourceHeader failed:", err)
|
||||
}
|
||||
got, n, err := unpackResource(buf, off, hdr)
|
||||
if err != nil {
|
||||
t.Fatal("Unpacking failed:", err)
|
||||
}
|
||||
if n != len(buf) {
|
||||
t.Errorf("Unpacked different amount than packed: got n = %d, want = %d", n, len(buf))
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Got = %+v, want = %+v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleHeaderSearch() {
|
||||
msg := Message{
|
||||
Header: Header{Response: true, Authoritative: true},
|
||||
Questions: []Question{
|
||||
{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeA,
|
||||
Class: ClassINET,
|
||||
},
|
||||
{
|
||||
Name: "bar.example.com.",
|
||||
Type: TypeA,
|
||||
Class: ClassINET,
|
||||
},
|
||||
},
|
||||
Answers: []Resource{
|
||||
&AResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeA,
|
||||
Class: ClassINET,
|
||||
},
|
||||
A: [4]byte{127, 0, 0, 1},
|
||||
},
|
||||
&AResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "bar.example.com.",
|
||||
Type: TypeA,
|
||||
Class: ClassINET,
|
||||
},
|
||||
A: [4]byte{127, 0, 0, 2},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
buf, err := msg.Pack()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
wantName := "bar.example.com."
|
||||
|
||||
var p Parser
|
||||
if _, err := p.Start(buf); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for {
|
||||
q, err := p.Question()
|
||||
if err == ErrSectionDone {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if q.Name != wantName {
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Println("Found question for name", wantName)
|
||||
if err := p.SkipAllQuestions(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
var gotIPs []net.IP
|
||||
for {
|
||||
h, err := p.AnswerHeader()
|
||||
if err == ErrSectionDone {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if (h.Type != TypeA && h.Type != TypeAAAA) || h.Class != ClassINET {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.EqualFold(h.Name, wantName) {
|
||||
if err := p.SkipAnswer(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
a, err := p.Answer()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch r := a.(type) {
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown type: %T", r))
|
||||
case *AResource:
|
||||
gotIPs = append(gotIPs, r.A[:])
|
||||
case *AAAAResource:
|
||||
gotIPs = append(gotIPs, r.AAAA[:])
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Found A/AAAA records for name %s: %v\n", wantName, gotIPs)
|
||||
|
||||
// Output:
|
||||
// Found question for name bar.example.com.
|
||||
// Found A/AAAA records for name bar.example.com.: [127.0.0.2]
|
||||
}
|
||||
|
||||
func largeTestMsg() Message {
|
||||
return Message{
|
||||
Header: Header{Response: true, Authoritative: true},
|
||||
Questions: []Question{
|
||||
{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeA,
|
||||
Class: ClassINET,
|
||||
},
|
||||
},
|
||||
Answers: []Resource{
|
||||
&AResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeA,
|
||||
Class: ClassINET,
|
||||
},
|
||||
A: [4]byte{127, 0, 0, 1},
|
||||
},
|
||||
&AResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeA,
|
||||
Class: ClassINET,
|
||||
},
|
||||
A: [4]byte{127, 0, 0, 2},
|
||||
},
|
||||
},
|
||||
Authorities: []Resource{
|
||||
&NSResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeNS,
|
||||
Class: ClassINET,
|
||||
},
|
||||
NS: "ns1.example.com.",
|
||||
},
|
||||
&NSResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeNS,
|
||||
Class: ClassINET,
|
||||
},
|
||||
NS: "ns2.example.com.",
|
||||
},
|
||||
},
|
||||
Additionals: []Resource{
|
||||
&TXTResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeTXT,
|
||||
Class: ClassINET,
|
||||
},
|
||||
Txt: "So Long, and Thanks for All the Fish",
|
||||
},
|
||||
&TXTResource{
|
||||
ResourceHeader: ResourceHeader{
|
||||
Name: "foo.bar.example.com.",
|
||||
Type: TypeTXT,
|
||||
Class: ClassINET,
|
||||
},
|
||||
Txt: "Hamster Huey and the Gooey Kablooie",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const loremIpsum = `
|
||||
Lorem ipsum dolor sit amet, nec enim antiopam id, an ullum choro
|
||||
nonumes qui, pro eu debet honestatis mediocritatem. No alia enim eos,
|
||||
magna signiferumque ex vis. Mei no aperiri dissentias, cu vel quas
|
||||
regione. Malorum quaeque vim ut, eum cu semper aliquid invidunt, ei
|
||||
nam ipsum assentior.
|
||||
|
||||
Nostrum appellantur usu no, vis ex probatus adipiscing. Cu usu illum
|
||||
facilis eleifend. Iusto conceptam complectitur vim id. Tale omnesque
|
||||
no usu, ei oblique sadipscing vim. At nullam voluptua usu, mei laudem
|
||||
reformidans et. Qui ei eros porro reformidans, ius suas veritus
|
||||
torquatos ex. Mea te facer alterum consequat.
|
||||
|
||||
Soleat torquatos democritum sed et, no mea congue appareat, facer
|
||||
aliquam nec in. Has te ipsum tritani. At justo dicta option nec, movet
|
||||
phaedrum ad nam. Ea detracto verterem liberavisse has, delectus
|
||||
suscipiantur in mei. Ex nam meliore complectitur. Ut nam omnis
|
||||
honestatis quaerendum, ea mea nihil affert detracto, ad vix rebum
|
||||
mollis.
|
||||
|
||||
Ut epicurei praesent neglegentur pri, prima fuisset intellegebat ad
|
||||
vim. An habemus comprehensam usu, at enim dignissim pro. Eam reque
|
||||
vivendum adipisci ea. Vel ne odio choro minimum. Sea admodum
|
||||
dissentiet ex. Mundi tamquam evertitur ius cu. Homero postea iisque ut
|
||||
pro, vel ne saepe senserit consetetur.
|
||||
|
||||
Nulla utamur facilisis ius ea, in viderer diceret pertinax eum. Mei no
|
||||
enim quodsi facilisi, ex sed aeterno appareat mediocritatem, eum
|
||||
sententiae deterruisset ut. At suas timeam euismod cum, offendit
|
||||
appareat interpretaris ne vix. Vel ea civibus albucius, ex vim quidam
|
||||
accusata intellegebat, noluisse instructior sea id. Nec te nonumes
|
||||
habemus appellantur, quis dignissim vituperata eu nam.
|
||||
|
||||
At vix apeirian patrioque vituperatoribus, an usu agam assum. Debet
|
||||
iisque an mea. Per eu dicant ponderum accommodare. Pri alienum
|
||||
placerat senserit an, ne eum ferri abhorreant vituperatoribus. Ut mea
|
||||
eligendi disputationi. Ius no tation everti impedit, ei magna quidam
|
||||
mediocritatem pri.
|
||||
|
||||
Legendos perpetua iracundia ne usu, no ius ullum epicurei intellegam,
|
||||
ad modus epicuri lucilius eam. In unum quaerendum usu. Ne diam paulo
|
||||
has, ea veri virtute sed. Alia honestatis conclusionemque mea eu, ut
|
||||
iudico albucius his.
|
||||
|
||||
Usu essent probatus eu, sed omnis dolor delicatissimi ex. No qui augue
|
||||
dissentias dissentiet. Laudem recteque no usu, vel an velit noluisse,
|
||||
an sed utinam eirmod appetere. Ne mea fuisset inimicus ocurreret. At
|
||||
vis dicant abhorreant, utinam forensibus nec ne, mei te docendi
|
||||
consequat. Brute inermis persecuti cum id. Ut ipsum munere propriae
|
||||
usu, dicit graeco disputando id has.
|
||||
|
||||
Eros dolore quaerendum nam ei. Timeam ornatus inciderint pro id. Nec
|
||||
torquatos sadipscing ei, ancillae molestie per in. Malis principes duo
|
||||
ea, usu liber postulant ei.
|
||||
|
||||
Graece timeam voluptatibus eu eam. Alia probatus quo no, ea scripta
|
||||
feugiat duo. Congue option meliore ex qui, noster invenire appellantur
|
||||
ea vel. Eu exerci legendos vel. Consetetur repudiandae vim ut. Vix an
|
||||
probo minimum, et nam illud falli tempor.
|
||||
|
||||
Cum dico signiferumque eu. Sed ut regione maiorum, id veritus insolens
|
||||
tacimates vix. Eu mel sint tamquam lucilius, duo no oporteat
|
||||
tacimates. Atqui augue concludaturque vix ei, id mel utroque menandri.
|
||||
|
||||
Ad oratio blandit aliquando pro. Vis et dolorum rationibus
|
||||
philosophia, ad cum nulla molestie. Hinc fuisset adversarium eum et,
|
||||
ne qui nisl verear saperet, vel te quaestio forensibus. Per odio
|
||||
option delenit an. Alii placerat has no, in pri nihil platonem
|
||||
cotidieque. Est ut elit copiosae scaevola, debet tollit maluisset sea
|
||||
an.
|
||||
|
||||
Te sea hinc debet pericula, liber ridens fabulas cu sed, quem mutat
|
||||
accusam mea et. Elitr labitur albucius et pri, an labore feugait mel.
|
||||
Velit zril melius usu ea. Ad stet putent interpretaris qui. Mel no
|
||||
error volumus scripserit. In pro paulo iudico, quo ei dolorem
|
||||
verterem, affert fabellas dissentiet ea vix.
|
||||
|
||||
Vis quot deserunt te. Error aliquid detraxit eu usu, vis alia eruditi
|
||||
salutatus cu. Est nostrud bonorum an, ei usu alii salutatus. Vel at
|
||||
nisl primis, eum ex aperiri noluisse reformidans. Ad veri velit
|
||||
utroque vis, ex equidem detraxit temporibus has.
|
||||
|
||||
Inermis appareat usu ne. Eros placerat periculis mea ad, in dictas
|
||||
pericula pro. Errem postulant at usu, ea nec amet ornatus mentitum. Ad
|
||||
mazim graeco eum, vel ex percipit volutpat iudicabit, sit ne delicata
|
||||
interesset. Mel sapientem prodesset abhorreant et, oblique suscipit
|
||||
eam id.
|
||||
|
||||
An maluisset disputando mea, vidit mnesarchum pri et. Malis insolens
|
||||
inciderint no sea. Ea persius maluisset vix, ne vim appellantur
|
||||
instructior, consul quidam definiebas pri id. Cum integre feugiat
|
||||
pericula in, ex sed persius similique, mel ne natum dicit percipitur.
|
||||
|
||||
Primis discere ne pri, errem putent definitionem at vis. Ei mel dolore
|
||||
neglegentur, mei tincidunt percipitur ei. Pro ad simul integre
|
||||
rationibus. Eu vel alii honestatis definitiones, mea no nonumy
|
||||
reprehendunt.
|
||||
|
||||
Dicta appareat legendos est cu. Eu vel congue dicunt omittam, no vix
|
||||
adhuc minimum constituam, quot noluisse id mel. Eu quot sale mutat
|
||||
duo, ex nisl munere invenire duo. Ne nec ullum utamur. Pro alterum
|
||||
debitis nostrum no, ut vel aliquid vivendo.
|
||||
|
||||
Aliquip fierent praesent quo ne, id sit audiam recusabo delicatissimi.
|
||||
Usu postulant incorrupte cu. At pro dicit tibique intellegam, cibo
|
||||
dolore impedit id eam, et aeque feugait assentior has. Quando sensibus
|
||||
nec ex. Possit sensibus pri ad, unum mutat periculis cu vix.
|
||||
|
||||
Mundi tibique vix te, duo simul partiendo qualisque id, est at vidit
|
||||
sonet tempor. No per solet aeterno deseruisse. Petentium salutandi
|
||||
definiebas pri cu. Munere vivendum est in. Ei justo congue eligendi
|
||||
vis, modus offendit omittantur te mel.
|
||||
|
||||
Integre voluptaria in qui, sit habemus tractatos constituam no. Utinam
|
||||
melius conceptam est ne, quo in minimum apeirian delicata, ut ius
|
||||
porro recusabo. Dicant expetenda vix no, ludus scripserit sed ex, eu
|
||||
his modo nostro. Ut etiam sonet his, quodsi inciderint philosophia te
|
||||
per. Nullam lobortis eu cum, vix an sonet efficiendi repudiandae. Vis
|
||||
ad idque fabellas intellegebat.
|
||||
|
||||
Eum commodo senserit conclusionemque ex. Sed forensibus sadipscing ut,
|
||||
mei in facer delicata periculis, sea ne hinc putent cetero. Nec ne
|
||||
alia corpora invenire, alia prima soleat te cum. Eleifend posidonium
|
||||
nam at.
|
||||
|
||||
Dolorum indoctum cu quo, ex dolor legendos recteque eam, cu pri zril
|
||||
discere. Nec civibus officiis dissentiunt ex, est te liber ludus
|
||||
elaboraret. Cum ea fabellas invenire. Ex vim nostrud eripuit
|
||||
comprehensam, nam te inermis delectus, saepe inermis senserit.
|
||||
`
|
||||
2
vendor/golang.org/x/net/http2/client_conn_pool.go
сгенерированный
поставляемый
@@ -247,7 +247,7 @@ func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
|
||||
}
|
||||
|
||||
// noDialClientConnPool is an implementation of http2.ClientConnPool
|
||||
// which never dials. We let the HTTP/1.1 client dial and use its TLS
|
||||
// which never dials. We let the HTTP/1.1 client dial and use its TLS
|
||||
// connection instead.
|
||||
type noDialClientConnPool struct{ *clientConnPool }
|
||||
|
||||
|
||||
146
vendor/golang.org/x/net/http2/databuffer.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,146 @@
|
||||
// Copyright 2014 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 http2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Buffer chunks are allocated from a pool to reduce pressure on GC.
|
||||
// The maximum wasted space per dataBuffer is 2x the largest size class,
|
||||
// which happens when the dataBuffer has multiple chunks and there is
|
||||
// one unread byte in both the first and last chunks. We use a few size
|
||||
// classes to minimize overheads for servers that typically receive very
|
||||
// small request bodies.
|
||||
//
|
||||
// TODO: Benchmark to determine if the pools are necessary. The GC may have
|
||||
// improved enough that we can instead allocate chunks like this:
|
||||
// make([]byte, max(16<<10, expectedBytesRemaining))
|
||||
var (
|
||||
dataChunkSizeClasses = []int{
|
||||
1 << 10,
|
||||
2 << 10,
|
||||
4 << 10,
|
||||
8 << 10,
|
||||
16 << 10,
|
||||
}
|
||||
dataChunkPools = [...]sync.Pool{
|
||||
{New: func() interface{} { return make([]byte, 1<<10) }},
|
||||
{New: func() interface{} { return make([]byte, 2<<10) }},
|
||||
{New: func() interface{} { return make([]byte, 4<<10) }},
|
||||
{New: func() interface{} { return make([]byte, 8<<10) }},
|
||||
{New: func() interface{} { return make([]byte, 16<<10) }},
|
||||
}
|
||||
)
|
||||
|
||||
func getDataBufferChunk(size int64) []byte {
|
||||
i := 0
|
||||
for ; i < len(dataChunkSizeClasses)-1; i++ {
|
||||
if size <= int64(dataChunkSizeClasses[i]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return dataChunkPools[i].Get().([]byte)
|
||||
}
|
||||
|
||||
func putDataBufferChunk(p []byte) {
|
||||
for i, n := range dataChunkSizeClasses {
|
||||
if len(p) == n {
|
||||
dataChunkPools[i].Put(p)
|
||||
return
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("unexpected buffer len=%v", len(p)))
|
||||
}
|
||||
|
||||
// dataBuffer is an io.ReadWriter backed by a list of data chunks.
|
||||
// Each dataBuffer is used to read DATA frames on a single stream.
|
||||
// The buffer is divided into chunks so the server can limit the
|
||||
// total memory used by a single connection without limiting the
|
||||
// request body size on any single stream.
|
||||
type dataBuffer struct {
|
||||
chunks [][]byte
|
||||
r int // next byte to read is chunks[0][r]
|
||||
w int // next byte to write is chunks[len(chunks)-1][w]
|
||||
size int // total buffered bytes
|
||||
expected int64 // we expect at least this many bytes in future Write calls (ignored if <= 0)
|
||||
}
|
||||
|
||||
var errReadEmpty = errors.New("read from empty dataBuffer")
|
||||
|
||||
// Read copies bytes from the buffer into p.
|
||||
// It is an error to read when no data is available.
|
||||
func (b *dataBuffer) Read(p []byte) (int, error) {
|
||||
if b.size == 0 {
|
||||
return 0, errReadEmpty
|
||||
}
|
||||
var ntotal int
|
||||
for len(p) > 0 && b.size > 0 {
|
||||
readFrom := b.bytesFromFirstChunk()
|
||||
n := copy(p, readFrom)
|
||||
p = p[n:]
|
||||
ntotal += n
|
||||
b.r += n
|
||||
b.size -= n
|
||||
// If the first chunk has been consumed, advance to the next chunk.
|
||||
if b.r == len(b.chunks[0]) {
|
||||
putDataBufferChunk(b.chunks[0])
|
||||
end := len(b.chunks) - 1
|
||||
copy(b.chunks[:end], b.chunks[1:])
|
||||
b.chunks[end] = nil
|
||||
b.chunks = b.chunks[:end]
|
||||
b.r = 0
|
||||
}
|
||||
}
|
||||
return ntotal, nil
|
||||
}
|
||||
|
||||
func (b *dataBuffer) bytesFromFirstChunk() []byte {
|
||||
if len(b.chunks) == 1 {
|
||||
return b.chunks[0][b.r:b.w]
|
||||
}
|
||||
return b.chunks[0][b.r:]
|
||||
}
|
||||
|
||||
// Len returns the number of bytes of the unread portion of the buffer.
|
||||
func (b *dataBuffer) Len() int {
|
||||
return b.size
|
||||
}
|
||||
|
||||
// Write appends p to the buffer.
|
||||
func (b *dataBuffer) Write(p []byte) (int, error) {
|
||||
ntotal := len(p)
|
||||
for len(p) > 0 {
|
||||
// If the last chunk is empty, allocate a new chunk. Try to allocate
|
||||
// enough to fully copy p plus any additional bytes we expect to
|
||||
// receive. However, this may allocate less than len(p).
|
||||
want := int64(len(p))
|
||||
if b.expected > want {
|
||||
want = b.expected
|
||||
}
|
||||
chunk := b.lastChunkOrAlloc(want)
|
||||
n := copy(chunk[b.w:], p)
|
||||
p = p[n:]
|
||||
b.w += n
|
||||
b.size += n
|
||||
b.expected -= int64(n)
|
||||
}
|
||||
return ntotal, nil
|
||||
}
|
||||
|
||||
func (b *dataBuffer) lastChunkOrAlloc(want int64) []byte {
|
||||
if len(b.chunks) != 0 {
|
||||
last := b.chunks[len(b.chunks)-1]
|
||||
if b.w < len(last) {
|
||||
return last
|
||||
}
|
||||
}
|
||||
chunk := getDataBufferChunk(want)
|
||||
b.chunks = append(b.chunks, chunk)
|
||||
b.w = 0
|
||||
return chunk
|
||||
}
|
||||
155
vendor/golang.org/x/net/http2/databuffer_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,155 @@
|
||||
// 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 http2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func fmtDataChunk(chunk []byte) string {
|
||||
out := ""
|
||||
var last byte
|
||||
var count int
|
||||
for _, c := range chunk {
|
||||
if c != last {
|
||||
if count > 0 {
|
||||
out += fmt.Sprintf(" x %d ", count)
|
||||
count = 0
|
||||
}
|
||||
out += string([]byte{c})
|
||||
last = c
|
||||
}
|
||||
count++
|
||||
}
|
||||
if count > 0 {
|
||||
out += fmt.Sprintf(" x %d", count)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func fmtDataChunks(chunks [][]byte) string {
|
||||
var out string
|
||||
for _, chunk := range chunks {
|
||||
out += fmt.Sprintf("{%q}", fmtDataChunk(chunk))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func testDataBuffer(t *testing.T, wantBytes []byte, setup func(t *testing.T) *dataBuffer) {
|
||||
// Run setup, then read the remaining bytes from the dataBuffer and check
|
||||
// that they match wantBytes. We use different read sizes to check corner
|
||||
// cases in Read.
|
||||
for _, readSize := range []int{1, 2, 1 * 1024, 32 * 1024} {
|
||||
t.Run(fmt.Sprintf("ReadSize=%d", readSize), func(t *testing.T) {
|
||||
b := setup(t)
|
||||
buf := make([]byte, readSize)
|
||||
var gotRead bytes.Buffer
|
||||
for {
|
||||
n, err := b.Read(buf)
|
||||
gotRead.Write(buf[:n])
|
||||
if err == errReadEmpty {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("error after %v bytes: %v", gotRead.Len(), err)
|
||||
}
|
||||
}
|
||||
if got, want := gotRead.Bytes(), wantBytes; !bytes.Equal(got, want) {
|
||||
t.Errorf("FinalRead=%q, want %q", fmtDataChunk(got), fmtDataChunk(want))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDataBufferAllocation(t *testing.T) {
|
||||
writes := [][]byte{
|
||||
bytes.Repeat([]byte("a"), 1*1024-1),
|
||||
[]byte{'a'},
|
||||
bytes.Repeat([]byte("b"), 4*1024-1),
|
||||
[]byte{'b'},
|
||||
bytes.Repeat([]byte("c"), 8*1024-1),
|
||||
[]byte{'c'},
|
||||
bytes.Repeat([]byte("d"), 16*1024-1),
|
||||
[]byte{'d'},
|
||||
bytes.Repeat([]byte("e"), 32*1024),
|
||||
}
|
||||
var wantRead bytes.Buffer
|
||||
for _, p := range writes {
|
||||
wantRead.Write(p)
|
||||
}
|
||||
|
||||
testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer {
|
||||
b := &dataBuffer{}
|
||||
for _, p := range writes {
|
||||
if n, err := b.Write(p); n != len(p) || err != nil {
|
||||
t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p))
|
||||
}
|
||||
}
|
||||
want := [][]byte{
|
||||
bytes.Repeat([]byte("a"), 1*1024),
|
||||
bytes.Repeat([]byte("b"), 4*1024),
|
||||
bytes.Repeat([]byte("c"), 8*1024),
|
||||
bytes.Repeat([]byte("d"), 16*1024),
|
||||
bytes.Repeat([]byte("e"), 16*1024),
|
||||
bytes.Repeat([]byte("e"), 16*1024),
|
||||
}
|
||||
if !reflect.DeepEqual(b.chunks, want) {
|
||||
t.Errorf("dataBuffer.chunks\ngot: %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want))
|
||||
}
|
||||
return b
|
||||
})
|
||||
}
|
||||
|
||||
func TestDataBufferAllocationWithExpected(t *testing.T) {
|
||||
writes := [][]byte{
|
||||
bytes.Repeat([]byte("a"), 1*1024), // allocates 16KB
|
||||
bytes.Repeat([]byte("b"), 14*1024),
|
||||
bytes.Repeat([]byte("c"), 15*1024), // allocates 16KB more
|
||||
bytes.Repeat([]byte("d"), 2*1024),
|
||||
bytes.Repeat([]byte("e"), 1*1024), // overflows 32KB expectation, allocates just 1KB
|
||||
}
|
||||
var wantRead bytes.Buffer
|
||||
for _, p := range writes {
|
||||
wantRead.Write(p)
|
||||
}
|
||||
|
||||
testDataBuffer(t, wantRead.Bytes(), func(t *testing.T) *dataBuffer {
|
||||
b := &dataBuffer{expected: 32 * 1024}
|
||||
for _, p := range writes {
|
||||
if n, err := b.Write(p); n != len(p) || err != nil {
|
||||
t.Fatalf("Write(%q x %d)=%v,%v want %v,nil", p[:1], len(p), n, err, len(p))
|
||||
}
|
||||
}
|
||||
want := [][]byte{
|
||||
append(bytes.Repeat([]byte("a"), 1*1024), append(bytes.Repeat([]byte("b"), 14*1024), bytes.Repeat([]byte("c"), 1*1024)...)...),
|
||||
append(bytes.Repeat([]byte("c"), 14*1024), bytes.Repeat([]byte("d"), 2*1024)...),
|
||||
bytes.Repeat([]byte("e"), 1*1024),
|
||||
}
|
||||
if !reflect.DeepEqual(b.chunks, want) {
|
||||
t.Errorf("dataBuffer.chunks\ngot: %s\nwant: %s", fmtDataChunks(b.chunks), fmtDataChunks(want))
|
||||
}
|
||||
return b
|
||||
})
|
||||
}
|
||||
|
||||
func TestDataBufferWriteAfterPartialRead(t *testing.T) {
|
||||
testDataBuffer(t, []byte("cdxyz"), func(t *testing.T) *dataBuffer {
|
||||
b := &dataBuffer{}
|
||||
if n, err := b.Write([]byte("abcd")); n != 4 || err != nil {
|
||||
t.Fatalf("Write(\"abcd\")=%v,%v want 4,nil", n, err)
|
||||
}
|
||||
p := make([]byte, 2)
|
||||
if n, err := b.Read(p); n != 2 || err != nil || !bytes.Equal(p, []byte("ab")) {
|
||||
t.Fatalf("Read()=%q,%v,%v want \"ab\",2,nil", p, n, err)
|
||||
}
|
||||
if n, err := b.Write([]byte("xyz")); n != 3 || err != nil {
|
||||
t.Fatalf("Write(\"xyz\")=%v,%v want 3,nil", n, err)
|
||||
}
|
||||
return b
|
||||
})
|
||||
}
|
||||
60
vendor/golang.org/x/net/http2/fixed_buffer.go
сгенерированный
поставляемый
@@ -1,60 +0,0 @@
|
||||
// Copyright 2014 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 http2
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
// fixedBuffer is an io.ReadWriter backed by a fixed size buffer.
|
||||
// It never allocates, but moves old data as new data is written.
|
||||
type fixedBuffer struct {
|
||||
buf []byte
|
||||
r, w int
|
||||
}
|
||||
|
||||
var (
|
||||
errReadEmpty = errors.New("read from empty fixedBuffer")
|
||||
errWriteFull = errors.New("write on full fixedBuffer")
|
||||
)
|
||||
|
||||
// Read copies bytes from the buffer into p.
|
||||
// It is an error to read when no data is available.
|
||||
func (b *fixedBuffer) Read(p []byte) (n int, err error) {
|
||||
if b.r == b.w {
|
||||
return 0, errReadEmpty
|
||||
}
|
||||
n = copy(p, b.buf[b.r:b.w])
|
||||
b.r += n
|
||||
if b.r == b.w {
|
||||
b.r = 0
|
||||
b.w = 0
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Len returns the number of bytes of the unread portion of the buffer.
|
||||
func (b *fixedBuffer) Len() int {
|
||||
return b.w - b.r
|
||||
}
|
||||
|
||||
// Write copies bytes from p into the buffer.
|
||||
// It is an error to write more data than the buffer can hold.
|
||||
func (b *fixedBuffer) Write(p []byte) (n int, err error) {
|
||||
// Slide existing data to beginning.
|
||||
if b.r > 0 && len(p) > len(b.buf)-b.w {
|
||||
copy(b.buf, b.buf[b.r:b.w])
|
||||
b.w -= b.r
|
||||
b.r = 0
|
||||
}
|
||||
|
||||
// Write new data.
|
||||
n = copy(b.buf[b.w:], p)
|
||||
b.w += n
|
||||
if n < len(p) {
|
||||
err = errWriteFull
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
128
vendor/golang.org/x/net/http2/fixed_buffer_test.go
сгенерированный
поставляемый
@@ -1,128 +0,0 @@
|
||||
// Copyright 2014 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 http2
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var bufferReadTests = []struct {
|
||||
buf fixedBuffer
|
||||
read, wn int
|
||||
werr error
|
||||
wp []byte
|
||||
wbuf fixedBuffer
|
||||
}{
|
||||
{
|
||||
fixedBuffer{[]byte{'a', 0}, 0, 1},
|
||||
5, 1, nil, []byte{'a'},
|
||||
fixedBuffer{[]byte{'a', 0}, 0, 0},
|
||||
},
|
||||
{
|
||||
fixedBuffer{[]byte{0, 'a'}, 1, 2},
|
||||
5, 1, nil, []byte{'a'},
|
||||
fixedBuffer{[]byte{0, 'a'}, 0, 0},
|
||||
},
|
||||
{
|
||||
fixedBuffer{[]byte{'a', 'b'}, 0, 2},
|
||||
1, 1, nil, []byte{'a'},
|
||||
fixedBuffer{[]byte{'a', 'b'}, 1, 2},
|
||||
},
|
||||
{
|
||||
fixedBuffer{[]byte{}, 0, 0},
|
||||
5, 0, errReadEmpty, []byte{},
|
||||
fixedBuffer{[]byte{}, 0, 0},
|
||||
},
|
||||
}
|
||||
|
||||
func TestBufferRead(t *testing.T) {
|
||||
for i, tt := range bufferReadTests {
|
||||
read := make([]byte, tt.read)
|
||||
n, err := tt.buf.Read(read)
|
||||
if n != tt.wn {
|
||||
t.Errorf("#%d: wn = %d want %d", i, n, tt.wn)
|
||||
continue
|
||||
}
|
||||
if err != tt.werr {
|
||||
t.Errorf("#%d: werr = %v want %v", i, err, tt.werr)
|
||||
continue
|
||||
}
|
||||
read = read[:n]
|
||||
if !reflect.DeepEqual(read, tt.wp) {
|
||||
t.Errorf("#%d: read = %+v want %+v", i, read, tt.wp)
|
||||
}
|
||||
if !reflect.DeepEqual(tt.buf, tt.wbuf) {
|
||||
t.Errorf("#%d: buf = %+v want %+v", i, tt.buf, tt.wbuf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var bufferWriteTests = []struct {
|
||||
buf fixedBuffer
|
||||
write, wn int
|
||||
werr error
|
||||
wbuf fixedBuffer
|
||||
}{
|
||||
{
|
||||
buf: fixedBuffer{
|
||||
buf: []byte{},
|
||||
},
|
||||
wbuf: fixedBuffer{
|
||||
buf: []byte{},
|
||||
},
|
||||
},
|
||||
{
|
||||
buf: fixedBuffer{
|
||||
buf: []byte{1, 'a'},
|
||||
},
|
||||
write: 1,
|
||||
wn: 1,
|
||||
wbuf: fixedBuffer{
|
||||
buf: []byte{0, 'a'},
|
||||
w: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
buf: fixedBuffer{
|
||||
buf: []byte{'a', 1},
|
||||
r: 1,
|
||||
w: 1,
|
||||
},
|
||||
write: 2,
|
||||
wn: 2,
|
||||
wbuf: fixedBuffer{
|
||||
buf: []byte{0, 0},
|
||||
w: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
buf: fixedBuffer{
|
||||
buf: []byte{},
|
||||
},
|
||||
write: 5,
|
||||
werr: errWriteFull,
|
||||
wbuf: fixedBuffer{
|
||||
buf: []byte{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestBufferWrite(t *testing.T) {
|
||||
for i, tt := range bufferWriteTests {
|
||||
n, err := tt.buf.Write(make([]byte, tt.write))
|
||||
if n != tt.wn {
|
||||
t.Errorf("#%d: wrote %d bytes; want %d", i, n, tt.wn)
|
||||
continue
|
||||
}
|
||||
if err != tt.werr {
|
||||
t.Errorf("#%d: error = %v; want %v", i, err, tt.werr)
|
||||
continue
|
||||
}
|
||||
if !reflect.DeepEqual(tt.buf, tt.wbuf) {
|
||||
t.Errorf("#%d: buf = %+v; want %+v", i, tt.buf, tt.wbuf)
|
||||
}
|
||||
}
|
||||
}
|
||||
81
vendor/golang.org/x/net/http2/frame.go
сгенерированный
поставляемый
@@ -122,7 +122,7 @@ var flagName = map[FrameType]map[Flags]string{
|
||||
// a frameParser parses a frame given its FrameHeader and payload
|
||||
// bytes. The length of payload will always equal fh.Length (which
|
||||
// might be 0).
|
||||
type frameParser func(fh FrameHeader, payload []byte) (Frame, error)
|
||||
type frameParser func(fc *frameCache, fh FrameHeader, payload []byte) (Frame, error)
|
||||
|
||||
var frameParsers = map[FrameType]frameParser{
|
||||
FrameData: parseDataFrame,
|
||||
@@ -312,7 +312,7 @@ type Framer struct {
|
||||
MaxHeaderListSize uint32
|
||||
|
||||
// TODO: track which type of frame & with which flags was sent
|
||||
// last. Then return an error (unless AllowIllegalWrites) if
|
||||
// last. Then return an error (unless AllowIllegalWrites) if
|
||||
// we're in the middle of a header block and a
|
||||
// non-Continuation or Continuation on a different stream is
|
||||
// attempted to be written.
|
||||
@@ -323,6 +323,8 @@ type Framer struct {
|
||||
debugFramerBuf *bytes.Buffer
|
||||
debugReadLoggerf func(string, ...interface{})
|
||||
debugWriteLoggerf func(string, ...interface{})
|
||||
|
||||
frameCache *frameCache // nil if frames aren't reused (default)
|
||||
}
|
||||
|
||||
func (fr *Framer) maxHeaderListSize() uint32 {
|
||||
@@ -398,6 +400,27 @@ const (
|
||||
maxFrameSize = 1<<24 - 1
|
||||
)
|
||||
|
||||
// SetReuseFrames allows the Framer to reuse Frames.
|
||||
// If called on a Framer, Frames returned by calls to ReadFrame are only
|
||||
// valid until the next call to ReadFrame.
|
||||
func (fr *Framer) SetReuseFrames() {
|
||||
if fr.frameCache != nil {
|
||||
return
|
||||
}
|
||||
fr.frameCache = &frameCache{}
|
||||
}
|
||||
|
||||
type frameCache struct {
|
||||
dataFrame DataFrame
|
||||
}
|
||||
|
||||
func (fc *frameCache) getDataFrame() *DataFrame {
|
||||
if fc == nil {
|
||||
return &DataFrame{}
|
||||
}
|
||||
return &fc.dataFrame
|
||||
}
|
||||
|
||||
// NewFramer returns a Framer that writes frames to w and reads them from r.
|
||||
func NewFramer(w io.Writer, r io.Reader) *Framer {
|
||||
fr := &Framer{
|
||||
@@ -477,7 +500,7 @@ func (fr *Framer) ReadFrame() (Frame, error) {
|
||||
if _, err := io.ReadFull(fr.r, payload); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := typeFrameParser(fh.Type)(fh, payload)
|
||||
f, err := typeFrameParser(fh.Type)(fr.frameCache, fh, payload)
|
||||
if err != nil {
|
||||
if ce, ok := err.(connError); ok {
|
||||
return nil, fr.connError(ce.Code, ce.Reason)
|
||||
@@ -565,7 +588,7 @@ func (f *DataFrame) Data() []byte {
|
||||
return f.data
|
||||
}
|
||||
|
||||
func parseDataFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||
func parseDataFrame(fc *frameCache, fh FrameHeader, payload []byte) (Frame, error) {
|
||||
if fh.StreamID == 0 {
|
||||
// DATA frames MUST be associated with a stream. If a
|
||||
// DATA frame is received whose stream identifier
|
||||
@@ -574,9 +597,9 @@ func parseDataFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||
// PROTOCOL_ERROR.
|
||||
return nil, connError{ErrCodeProtocol, "DATA frame with stream ID 0"}
|
||||
}
|
||||
f := &DataFrame{
|
||||
FrameHeader: fh,
|
||||
}
|
||||
f := fc.getDataFrame()
|
||||
f.FrameHeader = fh
|
||||
|
||||
var padSize byte
|
||||
if fh.Flags.Has(FlagDataPadded) {
|
||||
var err error
|
||||
@@ -600,6 +623,7 @@ var (
|
||||
errStreamID = errors.New("invalid stream ID")
|
||||
errDepStreamID = errors.New("invalid dependent stream ID")
|
||||
errPadLength = errors.New("pad length too large")
|
||||
errPadBytes = errors.New("padding bytes must all be zeros unless AllowIllegalWrites is enabled")
|
||||
)
|
||||
|
||||
func validStreamIDOrZero(streamID uint32) bool {
|
||||
@@ -623,6 +647,7 @@ func (f *Framer) WriteData(streamID uint32, endStream bool, data []byte) error {
|
||||
//
|
||||
// If pad is nil, the padding bit is not sent.
|
||||
// The length of pad must not exceed 255 bytes.
|
||||
// The bytes of pad must all be zero, unless f.AllowIllegalWrites is set.
|
||||
//
|
||||
// It will perform exactly one Write to the underlying Writer.
|
||||
// It is the caller's responsibility not to violate the maximum frame size
|
||||
@@ -631,8 +656,18 @@ func (f *Framer) WriteDataPadded(streamID uint32, endStream bool, data, pad []by
|
||||
if !validStreamID(streamID) && !f.AllowIllegalWrites {
|
||||
return errStreamID
|
||||
}
|
||||
if len(pad) > 255 {
|
||||
return errPadLength
|
||||
if len(pad) > 0 {
|
||||
if len(pad) > 255 {
|
||||
return errPadLength
|
||||
}
|
||||
if !f.AllowIllegalWrites {
|
||||
for _, b := range pad {
|
||||
if b != 0 {
|
||||
// "Padding octets MUST be set to zero when sending."
|
||||
return errPadBytes
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var flags Flags
|
||||
if endStream {
|
||||
@@ -660,10 +695,10 @@ type SettingsFrame struct {
|
||||
p []byte
|
||||
}
|
||||
|
||||
func parseSettingsFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||
func parseSettingsFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
|
||||
if fh.Flags.Has(FlagSettingsAck) && fh.Length > 0 {
|
||||
// When this (ACK 0x1) bit is set, the payload of the
|
||||
// SETTINGS frame MUST be empty. Receipt of a
|
||||
// SETTINGS frame MUST be empty. Receipt of a
|
||||
// SETTINGS frame with the ACK flag set and a length
|
||||
// field value other than 0 MUST be treated as a
|
||||
// connection error (Section 5.4.1) of type
|
||||
@@ -672,7 +707,7 @@ func parseSettingsFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||
}
|
||||
if fh.StreamID != 0 {
|
||||
// SETTINGS frames always apply to a connection,
|
||||
// never a single stream. The stream identifier for a
|
||||
// never a single stream. The stream identifier for a
|
||||
// SETTINGS frame MUST be zero (0x0). If an endpoint
|
||||
// receives a SETTINGS frame whose stream identifier
|
||||
// field is anything other than 0x0, the endpoint MUST
|
||||
@@ -762,7 +797,7 @@ type PingFrame struct {
|
||||
|
||||
func (f *PingFrame) IsAck() bool { return f.Flags.Has(FlagPingAck) }
|
||||
|
||||
func parsePingFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||
func parsePingFrame(_ *frameCache, fh FrameHeader, payload []byte) (Frame, error) {
|
||||
if len(payload) != 8 {
|
||||
return nil, ConnectionError(ErrCodeFrameSize)
|
||||
}
|
||||
@@ -802,7 +837,7 @@ func (f *GoAwayFrame) DebugData() []byte {
|
||||
return f.debugData
|
||||
}
|
||||
|
||||
func parseGoAwayFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||
func parseGoAwayFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
|
||||
if fh.StreamID != 0 {
|
||||
return nil, ConnectionError(ErrCodeProtocol)
|
||||
}
|
||||
@@ -842,7 +877,7 @@ func (f *UnknownFrame) Payload() []byte {
|
||||
return f.p
|
||||
}
|
||||
|
||||
func parseUnknownFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||
func parseUnknownFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
|
||||
return &UnknownFrame{fh, p}, nil
|
||||
}
|
||||
|
||||
@@ -853,7 +888,7 @@ type WindowUpdateFrame struct {
|
||||
Increment uint32 // never read with high bit set
|
||||
}
|
||||
|
||||
func parseWindowUpdateFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||
func parseWindowUpdateFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
|
||||
if len(p) != 4 {
|
||||
return nil, ConnectionError(ErrCodeFrameSize)
|
||||
}
|
||||
@@ -918,12 +953,12 @@ func (f *HeadersFrame) HasPriority() bool {
|
||||
return f.FrameHeader.Flags.Has(FlagHeadersPriority)
|
||||
}
|
||||
|
||||
func parseHeadersFrame(fh FrameHeader, p []byte) (_ Frame, err error) {
|
||||
func parseHeadersFrame(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err error) {
|
||||
hf := &HeadersFrame{
|
||||
FrameHeader: fh,
|
||||
}
|
||||
if fh.StreamID == 0 {
|
||||
// HEADERS frames MUST be associated with a stream. If a HEADERS frame
|
||||
// HEADERS frames MUST be associated with a stream. If a HEADERS frame
|
||||
// is received whose stream identifier field is 0x0, the recipient MUST
|
||||
// respond with a connection error (Section 5.4.1) of type
|
||||
// PROTOCOL_ERROR.
|
||||
@@ -1045,7 +1080,7 @@ type PriorityParam struct {
|
||||
Exclusive bool
|
||||
|
||||
// Weight is the stream's zero-indexed weight. It should be
|
||||
// set together with StreamDep, or neither should be set. Per
|
||||
// set together with StreamDep, or neither should be set. Per
|
||||
// the spec, "Add one to the value to obtain a weight between
|
||||
// 1 and 256."
|
||||
Weight uint8
|
||||
@@ -1055,7 +1090,7 @@ func (p PriorityParam) IsZero() bool {
|
||||
return p == PriorityParam{}
|
||||
}
|
||||
|
||||
func parsePriorityFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||
func parsePriorityFrame(_ *frameCache, fh FrameHeader, payload []byte) (Frame, error) {
|
||||
if fh.StreamID == 0 {
|
||||
return nil, connError{ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
|
||||
}
|
||||
@@ -1102,7 +1137,7 @@ type RSTStreamFrame struct {
|
||||
ErrCode ErrCode
|
||||
}
|
||||
|
||||
func parseRSTStreamFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||
func parseRSTStreamFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
|
||||
if len(p) != 4 {
|
||||
return nil, ConnectionError(ErrCodeFrameSize)
|
||||
}
|
||||
@@ -1132,7 +1167,7 @@ type ContinuationFrame struct {
|
||||
headerFragBuf []byte
|
||||
}
|
||||
|
||||
func parseContinuationFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||
func parseContinuationFrame(_ *frameCache, fh FrameHeader, p []byte) (Frame, error) {
|
||||
if fh.StreamID == 0 {
|
||||
return nil, connError{ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
|
||||
}
|
||||
@@ -1182,7 +1217,7 @@ func (f *PushPromiseFrame) HeadersEnded() bool {
|
||||
return f.FrameHeader.Flags.Has(FlagPushPromiseEndHeaders)
|
||||
}
|
||||
|
||||
func parsePushPromise(fh FrameHeader, p []byte) (_ Frame, err error) {
|
||||
func parsePushPromise(_ *frameCache, fh FrameHeader, p []byte) (_ Frame, err error) {
|
||||
pp := &PushPromiseFrame{
|
||||
FrameHeader: fh,
|
||||
}
|
||||
|
||||
91
vendor/golang.org/x/net/http2/frame_test.go
сгенерированный
поставляемый
@@ -141,7 +141,7 @@ func TestWriteDataPadded(t *testing.T) {
|
||||
streamID: 1,
|
||||
endStream: false,
|
||||
data: []byte("foo"),
|
||||
pad: []byte("bar"),
|
||||
pad: []byte{0, 0, 0},
|
||||
wantHeader: FrameHeader{
|
||||
Type: FrameData,
|
||||
Flags: FlagDataPadded,
|
||||
@@ -1096,6 +1096,95 @@ func TestMetaFrameHeader(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetReuseFrames(t *testing.T) {
|
||||
fr, buf := testFramer()
|
||||
fr.SetReuseFrames()
|
||||
|
||||
// Check that DataFrames are reused. Note that
|
||||
// SetReuseFrames only currently implements reuse of DataFrames.
|
||||
firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
|
||||
if df != firstDf {
|
||||
t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
df := readAndVerifyDataFrame("", 0, fr, buf, t)
|
||||
if df != firstDf {
|
||||
t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
df := readAndVerifyDataFrame("HHH", 3, fr, buf, t)
|
||||
if df != firstDf {
|
||||
t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetReuseFramesMoreThanOnce(t *testing.T) {
|
||||
fr, buf := testFramer()
|
||||
fr.SetReuseFrames()
|
||||
|
||||
firstDf := readAndVerifyDataFrame("ABC", 3, fr, buf, t)
|
||||
fr.SetReuseFrames()
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
|
||||
// SetReuseFrames should be idempotent
|
||||
fr.SetReuseFrames()
|
||||
if df != firstDf {
|
||||
t.Errorf("Expected Framer to return references to the same DataFrame. Have %v and %v", &df, &firstDf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNoSetReuseFrames(t *testing.T) {
|
||||
fr, buf := testFramer()
|
||||
const numNewDataFrames = 10
|
||||
dfSoFar := make([]interface{}, numNewDataFrames)
|
||||
|
||||
// Check that DataFrames are not reused if SetReuseFrames wasn't called.
|
||||
// SetReuseFrames only currently implements reuse of DataFrames.
|
||||
for i := 0; i < numNewDataFrames; i++ {
|
||||
df := readAndVerifyDataFrame("XYZ", 3, fr, buf, t)
|
||||
for _, item := range dfSoFar {
|
||||
if df == item {
|
||||
t.Errorf("Expected Framer to return new DataFrames since SetNoReuseFrames not set.")
|
||||
}
|
||||
}
|
||||
dfSoFar[i] = df
|
||||
}
|
||||
}
|
||||
|
||||
func readAndVerifyDataFrame(data string, length byte, fr *Framer, buf *bytes.Buffer, t *testing.T) *DataFrame {
|
||||
var streamID uint32 = 1<<24 + 2<<16 + 3<<8 + 4
|
||||
fr.WriteData(streamID, true, []byte(data))
|
||||
wantEnc := "\x00\x00" + string(length) + "\x00\x01\x01\x02\x03\x04" + data
|
||||
if buf.String() != wantEnc {
|
||||
t.Errorf("encoded as %q; want %q", buf.Bytes(), wantEnc)
|
||||
}
|
||||
f, err := fr.ReadFrame()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
df, ok := f.(*DataFrame)
|
||||
if !ok {
|
||||
t.Fatalf("got %T; want *DataFrame", f)
|
||||
}
|
||||
if !bytes.Equal(df.Data(), []byte(data)) {
|
||||
t.Errorf("got %q; want %q", df.Data(), []byte(data))
|
||||
}
|
||||
if f.Header().Flags&1 == 0 {
|
||||
t.Errorf("didn't see END_STREAM flag")
|
||||
}
|
||||
return df
|
||||
}
|
||||
|
||||
func encodeHeaderRaw(t *testing.T, pairs ...string) []byte {
|
||||
var he hpackEncoder
|
||||
return he.encodeHeaderRaw(t, pairs...)
|
||||
|
||||
6
vendor/golang.org/x/net/http2/go18.go
сгенерированный
поставляемый
@@ -12,7 +12,11 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func cloneTLSConfig(c *tls.Config) *tls.Config { return c.Clone() }
|
||||
func cloneTLSConfig(c *tls.Config) *tls.Config {
|
||||
c2 := c.Clone()
|
||||
c2.GetClientCertificate = c.GetClientCertificate // golang.org/issue/19264
|
||||
return c2
|
||||
}
|
||||
|
||||
var _ http.Pusher = (*responseWriter)(nil)
|
||||
|
||||
|
||||
13
vendor/golang.org/x/net/http2/go18_test.go
сгенерированный
поставляемый
@@ -7,6 +7,7 @@
|
||||
package http2
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -64,3 +65,15 @@ func TestConfigureServerIdleTimeout_Go18(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCertClone(t *testing.T) {
|
||||
c := &tls.Config{
|
||||
GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
panic("shouldn't be called")
|
||||
},
|
||||
}
|
||||
c2 := cloneTLSConfig(c)
|
||||
if c2.GetClientCertificate == nil {
|
||||
t.Error("GetClientCertificate is nil")
|
||||
}
|
||||
}
|
||||
|
||||
29
vendor/golang.org/x/net/http2/hpack/encode.go
сгенерированный
поставляемый
@@ -39,13 +39,14 @@ func NewEncoder(w io.Writer) *Encoder {
|
||||
tableSizeUpdate: false,
|
||||
w: w,
|
||||
}
|
||||
e.dynTab.table.init()
|
||||
e.dynTab.setMaxSize(initialHeaderTableSize)
|
||||
return e
|
||||
}
|
||||
|
||||
// WriteField encodes f into a single Write to e's underlying Writer.
|
||||
// This function may also produce bytes for "Header Table Size Update"
|
||||
// if necessary. If produced, it is done before encoding f.
|
||||
// if necessary. If produced, it is done before encoding f.
|
||||
func (e *Encoder) WriteField(f HeaderField) error {
|
||||
e.buf = e.buf[:0]
|
||||
|
||||
@@ -88,29 +89,17 @@ func (e *Encoder) WriteField(f HeaderField) error {
|
||||
// only name matches, i points to that index and nameValueMatch
|
||||
// becomes false.
|
||||
func (e *Encoder) searchTable(f HeaderField) (i uint64, nameValueMatch bool) {
|
||||
for idx, hf := range staticTable {
|
||||
if !constantTimeStringCompare(hf.Name, f.Name) {
|
||||
continue
|
||||
}
|
||||
if i == 0 {
|
||||
i = uint64(idx + 1)
|
||||
}
|
||||
if f.Sensitive {
|
||||
continue
|
||||
}
|
||||
if !constantTimeStringCompare(hf.Value, f.Value) {
|
||||
continue
|
||||
}
|
||||
i = uint64(idx + 1)
|
||||
nameValueMatch = true
|
||||
return
|
||||
i, nameValueMatch = staticTable.search(f)
|
||||
if nameValueMatch {
|
||||
return i, true
|
||||
}
|
||||
|
||||
j, nameValueMatch := e.dynTab.search(f)
|
||||
j, nameValueMatch := e.dynTab.table.search(f)
|
||||
if nameValueMatch || (i == 0 && j != 0) {
|
||||
i = j + uint64(len(staticTable))
|
||||
return j + uint64(staticTable.len()), nameValueMatch
|
||||
}
|
||||
return
|
||||
|
||||
return i, false
|
||||
}
|
||||
|
||||
// SetMaxDynamicTableSize changes the dynamic header table size to v.
|
||||
|
||||
70
vendor/golang.org/x/net/http2/hpack/encode_test.go
сгенерированный
поставляемый
@@ -7,6 +7,8 @@ package hpack
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -101,17 +103,20 @@ func TestEncoderSearchTable(t *testing.T) {
|
||||
wantMatch bool
|
||||
}{
|
||||
// Name and Value match
|
||||
{pair("foo", "bar"), uint64(len(staticTable) + 3), true},
|
||||
{pair("blake", "miz"), uint64(len(staticTable) + 2), true},
|
||||
{pair("foo", "bar"), uint64(staticTable.len()) + 3, true},
|
||||
{pair("blake", "miz"), uint64(staticTable.len()) + 2, true},
|
||||
{pair(":method", "GET"), 2, true},
|
||||
|
||||
// Only name match because Sensitive == true
|
||||
{HeaderField{":method", "GET", true}, 2, false},
|
||||
// Only name match because Sensitive == true. This is allowed to match
|
||||
// any ":method" entry. The current implementation uses the last entry
|
||||
// added in newStaticTable.
|
||||
{HeaderField{":method", "GET", true}, 3, false},
|
||||
|
||||
// Only Name matches
|
||||
{pair("foo", "..."), uint64(len(staticTable) + 3), false},
|
||||
{pair("blake", "..."), uint64(len(staticTable) + 2), false},
|
||||
{pair(":method", "..."), 2, false},
|
||||
{pair("foo", "..."), uint64(staticTable.len()) + 3, false},
|
||||
{pair("blake", "..."), uint64(staticTable.len()) + 2, false},
|
||||
// As before, this is allowed to match any ":method" entry.
|
||||
{pair(":method", "..."), 3, false},
|
||||
|
||||
// None match
|
||||
{pair("foo-", "bar"), 0, false},
|
||||
@@ -328,3 +333,54 @@ func TestEncoderSetMaxDynamicTableSizeLimit(t *testing.T) {
|
||||
func removeSpace(s string) string {
|
||||
return strings.Replace(s, " ", "", -1)
|
||||
}
|
||||
|
||||
func BenchmarkEncoderSearchTable(b *testing.B) {
|
||||
e := NewEncoder(nil)
|
||||
|
||||
// A sample of possible header fields.
|
||||
// This is not based on any actual data from HTTP/2 traces.
|
||||
var possible []HeaderField
|
||||
for _, f := range staticTable.ents {
|
||||
if f.Value == "" {
|
||||
possible = append(possible, f)
|
||||
continue
|
||||
}
|
||||
// Generate 5 random values, except for cookie and set-cookie,
|
||||
// which we know can have many values in practice.
|
||||
num := 5
|
||||
if f.Name == "cookie" || f.Name == "set-cookie" {
|
||||
num = 25
|
||||
}
|
||||
for i := 0; i < num; i++ {
|
||||
f.Value = fmt.Sprintf("%s-%d", f.Name, i)
|
||||
possible = append(possible, f)
|
||||
}
|
||||
}
|
||||
for k := 0; k < 10; k++ {
|
||||
f := HeaderField{
|
||||
Name: fmt.Sprintf("x-header-%d", k),
|
||||
Sensitive: rand.Int()%2 == 0,
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
f.Value = fmt.Sprintf("%s-%d", f.Name, i)
|
||||
possible = append(possible, f)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a random sample to the dynamic table. This very loosely simulates
|
||||
// a history of 100 requests with 20 header fields per request.
|
||||
for r := 0; r < 100*20; r++ {
|
||||
f := possible[rand.Int31n(int32(len(possible)))]
|
||||
// Skip if this is in the staticTable verbatim.
|
||||
if _, has := staticTable.search(f); !has {
|
||||
e.dynTab.add(f)
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
for _, f := range possible {
|
||||
e.searchTable(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
104
vendor/golang.org/x/net/http2/hpack/hpack.go
сгенерированный
поставляемый
@@ -61,7 +61,7 @@ func (hf HeaderField) String() string {
|
||||
func (hf HeaderField) Size() uint32 {
|
||||
// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
|
||||
// "The size of the dynamic table is the sum of the size of
|
||||
// its entries. The size of an entry is the sum of its name's
|
||||
// its entries. The size of an entry is the sum of its name's
|
||||
// length in octets (as defined in Section 5.2), its value's
|
||||
// length in octets (see Section 5.2), plus 32. The size of
|
||||
// an entry is calculated using the length of the name and
|
||||
@@ -102,6 +102,7 @@ func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decod
|
||||
emit: emitFunc,
|
||||
emitEnabled: true,
|
||||
}
|
||||
d.dynTab.table.init()
|
||||
d.dynTab.allowedMaxSize = maxDynamicTableSize
|
||||
d.dynTab.setMaxSize(maxDynamicTableSize)
|
||||
return d
|
||||
@@ -154,12 +155,9 @@ func (d *Decoder) SetAllowedMaxDynamicTableSize(v uint32) {
|
||||
}
|
||||
|
||||
type dynamicTable struct {
|
||||
// ents is the FIFO described at
|
||||
// http://http2.github.io/http2-spec/compression.html#rfc.section.2.3.2
|
||||
// The newest (low index) is append at the end, and items are
|
||||
// evicted from the front.
|
||||
ents []HeaderField
|
||||
size uint32
|
||||
table headerFieldTable
|
||||
size uint32 // in bytes
|
||||
maxSize uint32 // current maxSize
|
||||
allowedMaxSize uint32 // maxSize may go up to this, inclusive
|
||||
}
|
||||
@@ -169,95 +167,45 @@ func (dt *dynamicTable) setMaxSize(v uint32) {
|
||||
dt.evict()
|
||||
}
|
||||
|
||||
// TODO: change dynamicTable to be a struct with a slice and a size int field,
|
||||
// per http://http2.github.io/http2-spec/compression.html#rfc.section.4.1:
|
||||
//
|
||||
//
|
||||
// Then make add increment the size. maybe the max size should move from Decoder to
|
||||
// dynamicTable and add should return an ok bool if there was enough space.
|
||||
//
|
||||
// Later we'll need a remove operation on dynamicTable.
|
||||
|
||||
func (dt *dynamicTable) add(f HeaderField) {
|
||||
dt.ents = append(dt.ents, f)
|
||||
dt.table.addEntry(f)
|
||||
dt.size += f.Size()
|
||||
dt.evict()
|
||||
}
|
||||
|
||||
// If we're too big, evict old stuff (front of the slice)
|
||||
// If we're too big, evict old stuff.
|
||||
func (dt *dynamicTable) evict() {
|
||||
base := dt.ents // keep base pointer of slice
|
||||
for dt.size > dt.maxSize {
|
||||
dt.size -= dt.ents[0].Size()
|
||||
dt.ents = dt.ents[1:]
|
||||
var n int
|
||||
for dt.size > dt.maxSize && n < dt.table.len() {
|
||||
dt.size -= dt.table.ents[n].Size()
|
||||
n++
|
||||
}
|
||||
|
||||
// Shift slice contents down if we evicted things.
|
||||
if len(dt.ents) != len(base) {
|
||||
copy(base, dt.ents)
|
||||
dt.ents = base[:len(dt.ents)]
|
||||
}
|
||||
}
|
||||
|
||||
// constantTimeStringCompare compares string a and b in a constant
|
||||
// time manner.
|
||||
func constantTimeStringCompare(a, b string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
c := byte(0)
|
||||
|
||||
for i := 0; i < len(a); i++ {
|
||||
c |= a[i] ^ b[i]
|
||||
}
|
||||
|
||||
return c == 0
|
||||
}
|
||||
|
||||
// Search searches f in the table. The return value i is 0 if there is
|
||||
// no name match. If there is name match or name/value match, i is the
|
||||
// index of that entry (1-based). If both name and value match,
|
||||
// nameValueMatch becomes true.
|
||||
func (dt *dynamicTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
|
||||
l := len(dt.ents)
|
||||
for j := l - 1; j >= 0; j-- {
|
||||
ent := dt.ents[j]
|
||||
if !constantTimeStringCompare(ent.Name, f.Name) {
|
||||
continue
|
||||
}
|
||||
if i == 0 {
|
||||
i = uint64(l - j)
|
||||
}
|
||||
if f.Sensitive {
|
||||
continue
|
||||
}
|
||||
if !constantTimeStringCompare(ent.Value, f.Value) {
|
||||
continue
|
||||
}
|
||||
i = uint64(l - j)
|
||||
nameValueMatch = true
|
||||
return
|
||||
}
|
||||
return
|
||||
dt.table.evictOldest(n)
|
||||
}
|
||||
|
||||
func (d *Decoder) maxTableIndex() int {
|
||||
return len(d.dynTab.ents) + len(staticTable)
|
||||
// This should never overflow. RFC 7540 Section 6.5.2 limits the size of
|
||||
// the dynamic table to 2^32 bytes, where each entry will occupy more than
|
||||
// one byte. Further, the staticTable has a fixed, small length.
|
||||
return d.dynTab.table.len() + staticTable.len()
|
||||
}
|
||||
|
||||
func (d *Decoder) at(i uint64) (hf HeaderField, ok bool) {
|
||||
if i < 1 {
|
||||
// See Section 2.3.3.
|
||||
if i == 0 {
|
||||
return
|
||||
}
|
||||
if i <= uint64(staticTable.len()) {
|
||||
return staticTable.ents[i-1], true
|
||||
}
|
||||
if i > uint64(d.maxTableIndex()) {
|
||||
return
|
||||
}
|
||||
if i <= uint64(len(staticTable)) {
|
||||
return staticTable[i-1], true
|
||||
}
|
||||
dents := d.dynTab.ents
|
||||
return dents[len(dents)-(int(i)-len(staticTable))], true
|
||||
// In the dynamic table, newer entries have lower indices.
|
||||
// However, dt.ents[0] is the oldest entry. Hence, dt.ents is
|
||||
// the reversed dynamic table.
|
||||
dt := d.dynTab.table
|
||||
return dt.ents[dt.len()-(int(i)-staticTable.len())], true
|
||||
}
|
||||
|
||||
// Decode decodes an entire block.
|
||||
@@ -307,7 +255,7 @@ func (d *Decoder) Write(p []byte) (n int, err error) {
|
||||
err = d.parseHeaderFieldRepr()
|
||||
if err == errNeedMore {
|
||||
// Extra paranoia, making sure saveBuf won't
|
||||
// get too large. All the varint and string
|
||||
// get too large. All the varint and string
|
||||
// reading code earlier should already catch
|
||||
// overlong things and return ErrStringLength,
|
||||
// but keep this as a last resort.
|
||||
|
||||
146
vendor/golang.org/x/net/http2/hpack/hpack_test.go
сгенерированный
поставляемый
@@ -5,117 +5,16 @@
|
||||
package hpack
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestStaticTable(t *testing.T) {
|
||||
fromSpec := `
|
||||
+-------+-----------------------------+---------------+
|
||||
| 1 | :authority | |
|
||||
| 2 | :method | GET |
|
||||
| 3 | :method | POST |
|
||||
| 4 | :path | / |
|
||||
| 5 | :path | /index.html |
|
||||
| 6 | :scheme | http |
|
||||
| 7 | :scheme | https |
|
||||
| 8 | :status | 200 |
|
||||
| 9 | :status | 204 |
|
||||
| 10 | :status | 206 |
|
||||
| 11 | :status | 304 |
|
||||
| 12 | :status | 400 |
|
||||
| 13 | :status | 404 |
|
||||
| 14 | :status | 500 |
|
||||
| 15 | accept-charset | |
|
||||
| 16 | accept-encoding | gzip, deflate |
|
||||
| 17 | accept-language | |
|
||||
| 18 | accept-ranges | |
|
||||
| 19 | accept | |
|
||||
| 20 | access-control-allow-origin | |
|
||||
| 21 | age | |
|
||||
| 22 | allow | |
|
||||
| 23 | authorization | |
|
||||
| 24 | cache-control | |
|
||||
| 25 | content-disposition | |
|
||||
| 26 | content-encoding | |
|
||||
| 27 | content-language | |
|
||||
| 28 | content-length | |
|
||||
| 29 | content-location | |
|
||||
| 30 | content-range | |
|
||||
| 31 | content-type | |
|
||||
| 32 | cookie | |
|
||||
| 33 | date | |
|
||||
| 34 | etag | |
|
||||
| 35 | expect | |
|
||||
| 36 | expires | |
|
||||
| 37 | from | |
|
||||
| 38 | host | |
|
||||
| 39 | if-match | |
|
||||
| 40 | if-modified-since | |
|
||||
| 41 | if-none-match | |
|
||||
| 42 | if-range | |
|
||||
| 43 | if-unmodified-since | |
|
||||
| 44 | last-modified | |
|
||||
| 45 | link | |
|
||||
| 46 | location | |
|
||||
| 47 | max-forwards | |
|
||||
| 48 | proxy-authenticate | |
|
||||
| 49 | proxy-authorization | |
|
||||
| 50 | range | |
|
||||
| 51 | referer | |
|
||||
| 52 | refresh | |
|
||||
| 53 | retry-after | |
|
||||
| 54 | server | |
|
||||
| 55 | set-cookie | |
|
||||
| 56 | strict-transport-security | |
|
||||
| 57 | transfer-encoding | |
|
||||
| 58 | user-agent | |
|
||||
| 59 | vary | |
|
||||
| 60 | via | |
|
||||
| 61 | www-authenticate | |
|
||||
+-------+-----------------------------+---------------+
|
||||
`
|
||||
bs := bufio.NewScanner(strings.NewReader(fromSpec))
|
||||
re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
|
||||
for bs.Scan() {
|
||||
l := bs.Text()
|
||||
if !strings.Contains(l, "|") {
|
||||
continue
|
||||
}
|
||||
m := re.FindStringSubmatch(l)
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
i, err := strconv.Atoi(m[1])
|
||||
if err != nil {
|
||||
t.Errorf("Bogus integer on line %q", l)
|
||||
continue
|
||||
}
|
||||
if i < 1 || i > len(staticTable) {
|
||||
t.Errorf("Bogus index %d on line %q", i, l)
|
||||
continue
|
||||
}
|
||||
if got, want := staticTable[i-1].Name, m[2]; got != want {
|
||||
t.Errorf("header index %d name = %q; want %q", i, got, want)
|
||||
}
|
||||
if got, want := staticTable[i-1].Value, m[3]; got != want {
|
||||
t.Errorf("header index %d value = %q; want %q", i, got, want)
|
||||
}
|
||||
}
|
||||
if err := bs.Err(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) mustAt(idx int) HeaderField {
|
||||
if hf, ok := d.at(uint64(idx)); !ok {
|
||||
panic(fmt.Sprintf("bogus index %d", idx))
|
||||
@@ -132,10 +31,10 @@ func TestDynamicTableAt(t *testing.T) {
|
||||
}
|
||||
d.dynTab.add(pair("foo", "bar"))
|
||||
d.dynTab.add(pair("blake", "miz"))
|
||||
if got, want := at(len(staticTable)+1), (pair("blake", "miz")); got != want {
|
||||
if got, want := at(staticTable.len()+1), (pair("blake", "miz")); got != want {
|
||||
t.Errorf("at(dyn 1) = %v; want %v", got, want)
|
||||
}
|
||||
if got, want := at(len(staticTable)+2), (pair("foo", "bar")); got != want {
|
||||
if got, want := at(staticTable.len()+2), (pair("foo", "bar")); got != want {
|
||||
t.Errorf("at(dyn 2) = %v; want %v", got, want)
|
||||
}
|
||||
if got, want := at(3), (pair(":method", "POST")); got != want {
|
||||
@@ -143,41 +42,6 @@ func TestDynamicTableAt(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDynamicTableSearch(t *testing.T) {
|
||||
dt := dynamicTable{}
|
||||
dt.setMaxSize(4096)
|
||||
|
||||
dt.add(pair("foo", "bar"))
|
||||
dt.add(pair("blake", "miz"))
|
||||
dt.add(pair(":method", "GET"))
|
||||
|
||||
tests := []struct {
|
||||
hf HeaderField
|
||||
wantI uint64
|
||||
wantMatch bool
|
||||
}{
|
||||
// Name and Value match
|
||||
{pair("foo", "bar"), 3, true},
|
||||
{pair(":method", "GET"), 1, true},
|
||||
|
||||
// Only name match because of Sensitive == true
|
||||
{HeaderField{"blake", "miz", true}, 2, false},
|
||||
|
||||
// Only Name matches
|
||||
{pair("foo", "..."), 3, false},
|
||||
{pair("blake", "..."), 2, false},
|
||||
{pair(":method", "..."), 1, false},
|
||||
|
||||
// None match
|
||||
{pair("foo-", "bar"), 0, false},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
if gotI, gotMatch := dt.search(tt.hf); gotI != tt.wantI || gotMatch != tt.wantMatch {
|
||||
t.Errorf("d.search(%+v) = %v, %v; want %v, %v", tt.hf, gotI, gotMatch, tt.wantI, tt.wantMatch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDynamicTableSizeEvict(t *testing.T) {
|
||||
d := NewDecoder(4096, nil)
|
||||
if want := uint32(0); d.dynTab.size != want {
|
||||
@@ -196,7 +60,7 @@ func TestDynamicTableSizeEvict(t *testing.T) {
|
||||
if want := uint32(6 + 32); d.dynTab.size != want {
|
||||
t.Fatalf("after setMaxSize, size = %d; want %d", d.dynTab.size, want)
|
||||
}
|
||||
if got, want := d.mustAt(len(staticTable)+1), (pair("foo", "bar")); got != want {
|
||||
if got, want := d.mustAt(staticTable.len()+1), (pair("foo", "bar")); got != want {
|
||||
t.Errorf("at(dyn 1) = %v; want %v", got, want)
|
||||
}
|
||||
add(pair("long", strings.Repeat("x", 500)))
|
||||
@@ -255,9 +119,9 @@ func TestDecoderDecode(t *testing.T) {
|
||||
}
|
||||
|
||||
func (dt *dynamicTable) reverseCopy() (hf []HeaderField) {
|
||||
hf = make([]HeaderField, len(dt.ents))
|
||||
hf = make([]HeaderField, len(dt.table.ents))
|
||||
for i := range hf {
|
||||
hf[i] = dt.ents[len(dt.ents)-1-i]
|
||||
hf[i] = dt.table.ents[len(dt.table.ents)-1-i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
250
vendor/golang.org/x/net/http2/hpack/tables.go
сгенерированный
поставляемый
@@ -4,73 +4,199 @@
|
||||
|
||||
package hpack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// headerFieldTable implements a list of HeaderFields.
|
||||
// This is used to implement the static and dynamic tables.
|
||||
type headerFieldTable struct {
|
||||
// For static tables, entries are never evicted.
|
||||
//
|
||||
// For dynamic tables, entries are evicted from ents[0] and added to the end.
|
||||
// Each entry has a unique id that starts at one and increments for each
|
||||
// entry that is added. This unique id is stable across evictions, meaning
|
||||
// it can be used as a pointer to a specific entry. As in hpack, unique ids
|
||||
// are 1-based. The unique id for ents[k] is k + evictCount + 1.
|
||||
//
|
||||
// Zero is not a valid unique id.
|
||||
//
|
||||
// evictCount should not overflow in any remotely practical situation. In
|
||||
// practice, we will have one dynamic table per HTTP/2 connection. If we
|
||||
// assume a very powerful server that handles 1M QPS per connection and each
|
||||
// request adds (then evicts) 100 entries from the table, it would still take
|
||||
// 2M years for evictCount to overflow.
|
||||
ents []HeaderField
|
||||
evictCount uint64
|
||||
|
||||
// byName maps a HeaderField name to the unique id of the newest entry with
|
||||
// the same name. See above for a definition of "unique id".
|
||||
byName map[string]uint64
|
||||
|
||||
// byNameValue maps a HeaderField name/value pair to the unique id of the newest
|
||||
// entry with the same name and value. See above for a definition of "unique id".
|
||||
byNameValue map[pairNameValue]uint64
|
||||
}
|
||||
|
||||
type pairNameValue struct {
|
||||
name, value string
|
||||
}
|
||||
|
||||
func (t *headerFieldTable) init() {
|
||||
t.byName = make(map[string]uint64)
|
||||
t.byNameValue = make(map[pairNameValue]uint64)
|
||||
}
|
||||
|
||||
// len reports the number of entries in the table.
|
||||
func (t *headerFieldTable) len() int {
|
||||
return len(t.ents)
|
||||
}
|
||||
|
||||
// addEntry adds a new entry.
|
||||
func (t *headerFieldTable) addEntry(f HeaderField) {
|
||||
id := uint64(t.len()) + t.evictCount + 1
|
||||
t.byName[f.Name] = id
|
||||
t.byNameValue[pairNameValue{f.Name, f.Value}] = id
|
||||
t.ents = append(t.ents, f)
|
||||
}
|
||||
|
||||
// evictOldest evicts the n oldest entries in the table.
|
||||
func (t *headerFieldTable) evictOldest(n int) {
|
||||
if n > t.len() {
|
||||
panic(fmt.Sprintf("evictOldest(%v) on table with %v entries", n, t.len()))
|
||||
}
|
||||
for k := 0; k < n; k++ {
|
||||
f := t.ents[k]
|
||||
id := t.evictCount + uint64(k) + 1
|
||||
if t.byName[f.Name] == id {
|
||||
t.byName[f.Name] = 0
|
||||
}
|
||||
if p := (pairNameValue{f.Name, f.Value}); t.byNameValue[p] == id {
|
||||
t.byNameValue[p] = 0
|
||||
}
|
||||
}
|
||||
copy(t.ents, t.ents[n:])
|
||||
for k := t.len() - n; k < t.len(); k++ {
|
||||
t.ents[k] = HeaderField{} // so strings can be garbage collected
|
||||
}
|
||||
t.ents = t.ents[:t.len()-n]
|
||||
if t.evictCount+uint64(n) < t.evictCount {
|
||||
panic("evictCount overflow")
|
||||
}
|
||||
t.evictCount += uint64(n)
|
||||
}
|
||||
|
||||
// search finds f in the table. If there is no match, i is 0.
|
||||
// If both name and value match, i is the matched index and nameValueMatch
|
||||
// becomes true. If only name matches, i points to that index and
|
||||
// nameValueMatch becomes false.
|
||||
//
|
||||
// The returned index is a 1-based HPACK index. For dynamic tables, HPACK says
|
||||
// that index 1 should be the newest entry, but t.ents[0] is the oldest entry,
|
||||
// meaning t.ents is reversed for dynamic tables. Hence, when t is a dynamic
|
||||
// table, the return value i actually refers to the entry t.ents[t.len()-i].
|
||||
//
|
||||
// All tables are assumed to be a dynamic tables except for the global
|
||||
// staticTable pointer.
|
||||
//
|
||||
// See Section 2.3.3.
|
||||
func (t *headerFieldTable) search(f HeaderField) (i uint64, nameValueMatch bool) {
|
||||
if !f.Sensitive {
|
||||
if id := t.byNameValue[pairNameValue{f.Name, f.Value}]; id != 0 {
|
||||
return t.idToIndex(id), true
|
||||
}
|
||||
}
|
||||
if id := t.byName[f.Name]; id != 0 {
|
||||
return t.idToIndex(id), false
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// idToIndex converts a unique id to an HPACK index.
|
||||
// See Section 2.3.3.
|
||||
func (t *headerFieldTable) idToIndex(id uint64) uint64 {
|
||||
if id <= t.evictCount {
|
||||
panic(fmt.Sprintf("id (%v) <= evictCount (%v)", id, t.evictCount))
|
||||
}
|
||||
k := id - t.evictCount - 1 // convert id to an index t.ents[k]
|
||||
if t != staticTable {
|
||||
return uint64(t.len()) - k // dynamic table
|
||||
}
|
||||
return k + 1
|
||||
}
|
||||
|
||||
func pair(name, value string) HeaderField {
|
||||
return HeaderField{Name: name, Value: value}
|
||||
}
|
||||
|
||||
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
|
||||
var staticTable = [...]HeaderField{
|
||||
pair(":authority", ""), // index 1 (1-based)
|
||||
pair(":method", "GET"),
|
||||
pair(":method", "POST"),
|
||||
pair(":path", "/"),
|
||||
pair(":path", "/index.html"),
|
||||
pair(":scheme", "http"),
|
||||
pair(":scheme", "https"),
|
||||
pair(":status", "200"),
|
||||
pair(":status", "204"),
|
||||
pair(":status", "206"),
|
||||
pair(":status", "304"),
|
||||
pair(":status", "400"),
|
||||
pair(":status", "404"),
|
||||
pair(":status", "500"),
|
||||
pair("accept-charset", ""),
|
||||
pair("accept-encoding", "gzip, deflate"),
|
||||
pair("accept-language", ""),
|
||||
pair("accept-ranges", ""),
|
||||
pair("accept", ""),
|
||||
pair("access-control-allow-origin", ""),
|
||||
pair("age", ""),
|
||||
pair("allow", ""),
|
||||
pair("authorization", ""),
|
||||
pair("cache-control", ""),
|
||||
pair("content-disposition", ""),
|
||||
pair("content-encoding", ""),
|
||||
pair("content-language", ""),
|
||||
pair("content-length", ""),
|
||||
pair("content-location", ""),
|
||||
pair("content-range", ""),
|
||||
pair("content-type", ""),
|
||||
pair("cookie", ""),
|
||||
pair("date", ""),
|
||||
pair("etag", ""),
|
||||
pair("expect", ""),
|
||||
pair("expires", ""),
|
||||
pair("from", ""),
|
||||
pair("host", ""),
|
||||
pair("if-match", ""),
|
||||
pair("if-modified-since", ""),
|
||||
pair("if-none-match", ""),
|
||||
pair("if-range", ""),
|
||||
pair("if-unmodified-since", ""),
|
||||
pair("last-modified", ""),
|
||||
pair("link", ""),
|
||||
pair("location", ""),
|
||||
pair("max-forwards", ""),
|
||||
pair("proxy-authenticate", ""),
|
||||
pair("proxy-authorization", ""),
|
||||
pair("range", ""),
|
||||
pair("referer", ""),
|
||||
pair("refresh", ""),
|
||||
pair("retry-after", ""),
|
||||
pair("server", ""),
|
||||
pair("set-cookie", ""),
|
||||
pair("strict-transport-security", ""),
|
||||
pair("transfer-encoding", ""),
|
||||
pair("user-agent", ""),
|
||||
pair("vary", ""),
|
||||
pair("via", ""),
|
||||
pair("www-authenticate", ""),
|
||||
var staticTable = newStaticTable()
|
||||
|
||||
func newStaticTable() *headerFieldTable {
|
||||
t := &headerFieldTable{}
|
||||
t.init()
|
||||
t.addEntry(pair(":authority", ""))
|
||||
t.addEntry(pair(":method", "GET"))
|
||||
t.addEntry(pair(":method", "POST"))
|
||||
t.addEntry(pair(":path", "/"))
|
||||
t.addEntry(pair(":path", "/index.html"))
|
||||
t.addEntry(pair(":scheme", "http"))
|
||||
t.addEntry(pair(":scheme", "https"))
|
||||
t.addEntry(pair(":status", "200"))
|
||||
t.addEntry(pair(":status", "204"))
|
||||
t.addEntry(pair(":status", "206"))
|
||||
t.addEntry(pair(":status", "304"))
|
||||
t.addEntry(pair(":status", "400"))
|
||||
t.addEntry(pair(":status", "404"))
|
||||
t.addEntry(pair(":status", "500"))
|
||||
t.addEntry(pair("accept-charset", ""))
|
||||
t.addEntry(pair("accept-encoding", "gzip, deflate"))
|
||||
t.addEntry(pair("accept-language", ""))
|
||||
t.addEntry(pair("accept-ranges", ""))
|
||||
t.addEntry(pair("accept", ""))
|
||||
t.addEntry(pair("access-control-allow-origin", ""))
|
||||
t.addEntry(pair("age", ""))
|
||||
t.addEntry(pair("allow", ""))
|
||||
t.addEntry(pair("authorization", ""))
|
||||
t.addEntry(pair("cache-control", ""))
|
||||
t.addEntry(pair("content-disposition", ""))
|
||||
t.addEntry(pair("content-encoding", ""))
|
||||
t.addEntry(pair("content-language", ""))
|
||||
t.addEntry(pair("content-length", ""))
|
||||
t.addEntry(pair("content-location", ""))
|
||||
t.addEntry(pair("content-range", ""))
|
||||
t.addEntry(pair("content-type", ""))
|
||||
t.addEntry(pair("cookie", ""))
|
||||
t.addEntry(pair("date", ""))
|
||||
t.addEntry(pair("etag", ""))
|
||||
t.addEntry(pair("expect", ""))
|
||||
t.addEntry(pair("expires", ""))
|
||||
t.addEntry(pair("from", ""))
|
||||
t.addEntry(pair("host", ""))
|
||||
t.addEntry(pair("if-match", ""))
|
||||
t.addEntry(pair("if-modified-since", ""))
|
||||
t.addEntry(pair("if-none-match", ""))
|
||||
t.addEntry(pair("if-range", ""))
|
||||
t.addEntry(pair("if-unmodified-since", ""))
|
||||
t.addEntry(pair("last-modified", ""))
|
||||
t.addEntry(pair("link", ""))
|
||||
t.addEntry(pair("location", ""))
|
||||
t.addEntry(pair("max-forwards", ""))
|
||||
t.addEntry(pair("proxy-authenticate", ""))
|
||||
t.addEntry(pair("proxy-authorization", ""))
|
||||
t.addEntry(pair("range", ""))
|
||||
t.addEntry(pair("referer", ""))
|
||||
t.addEntry(pair("refresh", ""))
|
||||
t.addEntry(pair("retry-after", ""))
|
||||
t.addEntry(pair("server", ""))
|
||||
t.addEntry(pair("set-cookie", ""))
|
||||
t.addEntry(pair("strict-transport-security", ""))
|
||||
t.addEntry(pair("transfer-encoding", ""))
|
||||
t.addEntry(pair("user-agent", ""))
|
||||
t.addEntry(pair("vary", ""))
|
||||
t.addEntry(pair("via", ""))
|
||||
t.addEntry(pair("www-authenticate", ""))
|
||||
return t
|
||||
}
|
||||
|
||||
var huffmanCodes = [256]uint32{
|
||||
|
||||
188
vendor/golang.org/x/net/http2/hpack/tables_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,188 @@
|
||||
// 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 hpack
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHeaderFieldTable(t *testing.T) {
|
||||
table := &headerFieldTable{}
|
||||
table.init()
|
||||
table.addEntry(pair("key1", "value1-1"))
|
||||
table.addEntry(pair("key2", "value2-1"))
|
||||
table.addEntry(pair("key1", "value1-2"))
|
||||
table.addEntry(pair("key3", "value3-1"))
|
||||
table.addEntry(pair("key4", "value4-1"))
|
||||
table.addEntry(pair("key2", "value2-2"))
|
||||
|
||||
// Tests will be run twice: once before evicting anything, and
|
||||
// again after evicting the three oldest entries.
|
||||
tests := []struct {
|
||||
f HeaderField
|
||||
beforeWantStaticI uint64
|
||||
beforeWantMatch bool
|
||||
afterWantStaticI uint64
|
||||
afterWantMatch bool
|
||||
}{
|
||||
{HeaderField{"key1", "value1-1", false}, 1, true, 0, false},
|
||||
{HeaderField{"key1", "value1-2", false}, 3, true, 0, false},
|
||||
{HeaderField{"key1", "value1-3", false}, 3, false, 0, false},
|
||||
{HeaderField{"key2", "value2-1", false}, 2, true, 3, false},
|
||||
{HeaderField{"key2", "value2-2", false}, 6, true, 3, true},
|
||||
{HeaderField{"key2", "value2-3", false}, 6, false, 3, false},
|
||||
{HeaderField{"key4", "value4-1", false}, 5, true, 2, true},
|
||||
// Name match only, because sensitive.
|
||||
{HeaderField{"key4", "value4-1", true}, 5, false, 2, false},
|
||||
// Key not found.
|
||||
{HeaderField{"key5", "value5-x", false}, 0, false, 0, false},
|
||||
}
|
||||
|
||||
staticToDynamic := func(i uint64) uint64 {
|
||||
if i == 0 {
|
||||
return 0
|
||||
}
|
||||
return uint64(table.len()) - i + 1 // dynamic is the reversed table
|
||||
}
|
||||
|
||||
searchStatic := func(f HeaderField) (uint64, bool) {
|
||||
old := staticTable
|
||||
staticTable = table
|
||||
defer func() { staticTable = old }()
|
||||
return staticTable.search(f)
|
||||
}
|
||||
|
||||
searchDynamic := func(f HeaderField) (uint64, bool) {
|
||||
return table.search(f)
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
gotI, gotMatch := searchStatic(test.f)
|
||||
if wantI, wantMatch := test.beforeWantStaticI, test.beforeWantMatch; gotI != wantI || gotMatch != wantMatch {
|
||||
t.Errorf("before evictions: searchStatic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch)
|
||||
}
|
||||
gotI, gotMatch = searchDynamic(test.f)
|
||||
wantDynamicI := staticToDynamic(test.beforeWantStaticI)
|
||||
if wantI, wantMatch := wantDynamicI, test.beforeWantMatch; gotI != wantI || gotMatch != wantMatch {
|
||||
t.Errorf("before evictions: searchDynamic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch)
|
||||
}
|
||||
}
|
||||
|
||||
table.evictOldest(3)
|
||||
|
||||
for _, test := range tests {
|
||||
gotI, gotMatch := searchStatic(test.f)
|
||||
if wantI, wantMatch := test.afterWantStaticI, test.afterWantMatch; gotI != wantI || gotMatch != wantMatch {
|
||||
t.Errorf("after evictions: searchStatic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch)
|
||||
}
|
||||
gotI, gotMatch = searchDynamic(test.f)
|
||||
wantDynamicI := staticToDynamic(test.afterWantStaticI)
|
||||
if wantI, wantMatch := wantDynamicI, test.afterWantMatch; gotI != wantI || gotMatch != wantMatch {
|
||||
t.Errorf("after evictions: searchDynamic(%+v)=%v,%v want %v,%v", test.f, gotI, gotMatch, wantI, wantMatch)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStaticTable(t *testing.T) {
|
||||
fromSpec := `
|
||||
+-------+-----------------------------+---------------+
|
||||
| 1 | :authority | |
|
||||
| 2 | :method | GET |
|
||||
| 3 | :method | POST |
|
||||
| 4 | :path | / |
|
||||
| 5 | :path | /index.html |
|
||||
| 6 | :scheme | http |
|
||||
| 7 | :scheme | https |
|
||||
| 8 | :status | 200 |
|
||||
| 9 | :status | 204 |
|
||||
| 10 | :status | 206 |
|
||||
| 11 | :status | 304 |
|
||||
| 12 | :status | 400 |
|
||||
| 13 | :status | 404 |
|
||||
| 14 | :status | 500 |
|
||||
| 15 | accept-charset | |
|
||||
| 16 | accept-encoding | gzip, deflate |
|
||||
| 17 | accept-language | |
|
||||
| 18 | accept-ranges | |
|
||||
| 19 | accept | |
|
||||
| 20 | access-control-allow-origin | |
|
||||
| 21 | age | |
|
||||
| 22 | allow | |
|
||||
| 23 | authorization | |
|
||||
| 24 | cache-control | |
|
||||
| 25 | content-disposition | |
|
||||
| 26 | content-encoding | |
|
||||
| 27 | content-language | |
|
||||
| 28 | content-length | |
|
||||
| 29 | content-location | |
|
||||
| 30 | content-range | |
|
||||
| 31 | content-type | |
|
||||
| 32 | cookie | |
|
||||
| 33 | date | |
|
||||
| 34 | etag | |
|
||||
| 35 | expect | |
|
||||
| 36 | expires | |
|
||||
| 37 | from | |
|
||||
| 38 | host | |
|
||||
| 39 | if-match | |
|
||||
| 40 | if-modified-since | |
|
||||
| 41 | if-none-match | |
|
||||
| 42 | if-range | |
|
||||
| 43 | if-unmodified-since | |
|
||||
| 44 | last-modified | |
|
||||
| 45 | link | |
|
||||
| 46 | location | |
|
||||
| 47 | max-forwards | |
|
||||
| 48 | proxy-authenticate | |
|
||||
| 49 | proxy-authorization | |
|
||||
| 50 | range | |
|
||||
| 51 | referer | |
|
||||
| 52 | refresh | |
|
||||
| 53 | retry-after | |
|
||||
| 54 | server | |
|
||||
| 55 | set-cookie | |
|
||||
| 56 | strict-transport-security | |
|
||||
| 57 | transfer-encoding | |
|
||||
| 58 | user-agent | |
|
||||
| 59 | vary | |
|
||||
| 60 | via | |
|
||||
| 61 | www-authenticate | |
|
||||
+-------+-----------------------------+---------------+
|
||||
`
|
||||
bs := bufio.NewScanner(strings.NewReader(fromSpec))
|
||||
re := regexp.MustCompile(`\| (\d+)\s+\| (\S+)\s*\| (\S(.*\S)?)?\s+\|`)
|
||||
for bs.Scan() {
|
||||
l := bs.Text()
|
||||
if !strings.Contains(l, "|") {
|
||||
continue
|
||||
}
|
||||
m := re.FindStringSubmatch(l)
|
||||
if m == nil {
|
||||
continue
|
||||
}
|
||||
i, err := strconv.Atoi(m[1])
|
||||
if err != nil {
|
||||
t.Errorf("Bogus integer on line %q", l)
|
||||
continue
|
||||
}
|
||||
if i < 1 || i > staticTable.len() {
|
||||
t.Errorf("Bogus index %d on line %q", i, l)
|
||||
continue
|
||||
}
|
||||
if got, want := staticTable.ents[i-1].Name, m[2]; got != want {
|
||||
t.Errorf("header index %d name = %q; want %q", i, got, want)
|
||||
}
|
||||
if got, want := staticTable.ents[i-1].Value, m[3]; got != want {
|
||||
t.Errorf("header index %d value = %q; want %q", i, got, want)
|
||||
}
|
||||
}
|
||||
if err := bs.Err(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
2
vendor/golang.org/x/net/http2/pipe.go
сгенерированный
поставляемый
@@ -10,7 +10,7 @@ import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
|
||||
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
|
||||
// io.Pipe except there are no PipeReader/PipeWriter halves, and the
|
||||
// underlying buffer is an interface. (io.Pipe is always unbuffered)
|
||||
type pipe struct {
|
||||
|
||||
199
vendor/golang.org/x/net/http2/server.go
сгенерированный
поставляемый
@@ -110,11 +110,38 @@ type Server struct {
|
||||
// activity for the purposes of IdleTimeout.
|
||||
IdleTimeout time.Duration
|
||||
|
||||
// MaxUploadBufferPerConnection is the size of the initial flow
|
||||
// control window for each connections. The HTTP/2 spec does not
|
||||
// allow this to be smaller than 65535 or larger than 2^32-1.
|
||||
// If the value is outside this range, a default value will be
|
||||
// used instead.
|
||||
MaxUploadBufferPerConnection int32
|
||||
|
||||
// MaxUploadBufferPerStream is the size of the initial flow control
|
||||
// window for each stream. The HTTP/2 spec does not allow this to
|
||||
// be larger than 2^32-1. If the value is zero or larger than the
|
||||
// maximum, a default value will be used instead.
|
||||
MaxUploadBufferPerStream int32
|
||||
|
||||
// NewWriteScheduler constructs a write scheduler for a connection.
|
||||
// If nil, a default scheduler is chosen.
|
||||
NewWriteScheduler func() WriteScheduler
|
||||
}
|
||||
|
||||
func (s *Server) initialConnRecvWindowSize() int32 {
|
||||
if s.MaxUploadBufferPerConnection > initialWindowSize {
|
||||
return s.MaxUploadBufferPerConnection
|
||||
}
|
||||
return 1 << 20
|
||||
}
|
||||
|
||||
func (s *Server) initialStreamRecvWindowSize() int32 {
|
||||
if s.MaxUploadBufferPerStream > 0 {
|
||||
return s.MaxUploadBufferPerStream
|
||||
}
|
||||
return 1 << 20
|
||||
}
|
||||
|
||||
func (s *Server) maxReadFrameSize() uint32 {
|
||||
if v := s.MaxReadFrameSize; v >= minMaxFrameSize && v <= maxFrameSize {
|
||||
return v
|
||||
@@ -255,27 +282,27 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
||||
defer cancel()
|
||||
|
||||
sc := &serverConn{
|
||||
srv: s,
|
||||
hs: opts.baseConfig(),
|
||||
conn: c,
|
||||
baseCtx: baseCtx,
|
||||
remoteAddrStr: c.RemoteAddr().String(),
|
||||
bw: newBufferedWriter(c),
|
||||
handler: opts.handler(),
|
||||
streams: make(map[uint32]*stream),
|
||||
readFrameCh: make(chan readFrameResult),
|
||||
wantWriteFrameCh: make(chan FrameWriteRequest, 8),
|
||||
wantStartPushCh: make(chan startPushRequest, 8),
|
||||
wroteFrameCh: make(chan frameWriteResult, 1), // buffered; one send in writeFrameAsync
|
||||
bodyReadCh: make(chan bodyReadMsg), // buffering doesn't matter either way
|
||||
doneServing: make(chan struct{}),
|
||||
clientMaxStreams: math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value"
|
||||
advMaxStreams: s.maxConcurrentStreams(),
|
||||
initialWindowSize: initialWindowSize,
|
||||
maxFrameSize: initialMaxFrameSize,
|
||||
headerTableSize: initialHeaderTableSize,
|
||||
serveG: newGoroutineLock(),
|
||||
pushEnabled: true,
|
||||
srv: s,
|
||||
hs: opts.baseConfig(),
|
||||
conn: c,
|
||||
baseCtx: baseCtx,
|
||||
remoteAddrStr: c.RemoteAddr().String(),
|
||||
bw: newBufferedWriter(c),
|
||||
handler: opts.handler(),
|
||||
streams: make(map[uint32]*stream),
|
||||
readFrameCh: make(chan readFrameResult),
|
||||
wantWriteFrameCh: make(chan FrameWriteRequest, 8),
|
||||
wantStartPushCh: make(chan startPushRequest, 8),
|
||||
wroteFrameCh: make(chan frameWriteResult, 1), // buffered; one send in writeFrameAsync
|
||||
bodyReadCh: make(chan bodyReadMsg), // buffering doesn't matter either way
|
||||
doneServing: make(chan struct{}),
|
||||
clientMaxStreams: math.MaxUint32, // Section 6.5.2: "Initially, there is no limit to this value"
|
||||
advMaxStreams: s.maxConcurrentStreams(),
|
||||
initialStreamSendWindowSize: initialWindowSize,
|
||||
maxFrameSize: initialMaxFrameSize,
|
||||
headerTableSize: initialHeaderTableSize,
|
||||
serveG: newGoroutineLock(),
|
||||
pushEnabled: true,
|
||||
}
|
||||
|
||||
// The net/http package sets the write deadline from the
|
||||
@@ -294,6 +321,9 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
|
||||
sc.writeSched = NewRandomWriteScheduler()
|
||||
}
|
||||
|
||||
// These start at the RFC-specified defaults. If there is a higher
|
||||
// configured value for inflow, that will be updated when we send a
|
||||
// WINDOW_UPDATE shortly after sending SETTINGS.
|
||||
sc.flow.add(initialWindowSize)
|
||||
sc.inflow.add(initialWindowSize)
|
||||
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
|
||||
@@ -387,34 +417,34 @@ type serverConn struct {
|
||||
writeSched WriteScheduler
|
||||
|
||||
// Everything following is owned by the serve loop; use serveG.check():
|
||||
serveG goroutineLock // used to verify funcs are on serve()
|
||||
pushEnabled bool
|
||||
sawFirstSettings bool // got the initial SETTINGS frame after the preface
|
||||
needToSendSettingsAck bool
|
||||
unackedSettings int // how many SETTINGS have we sent without ACKs?
|
||||
clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
|
||||
advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
|
||||
curClientStreams uint32 // number of open streams initiated by the client
|
||||
curPushedStreams uint32 // number of open streams initiated by server push
|
||||
maxClientStreamID uint32 // max ever seen from client (odd), or 0 if there have been no client requests
|
||||
maxPushPromiseID uint32 // ID of the last push promise (even), or 0 if there have been no pushes
|
||||
streams map[uint32]*stream
|
||||
initialWindowSize int32
|
||||
maxFrameSize int32
|
||||
headerTableSize uint32
|
||||
peerMaxHeaderListSize uint32 // zero means unknown (default)
|
||||
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
|
||||
writingFrame bool // started writing a frame (on serve goroutine or separate)
|
||||
writingFrameAsync bool // started a frame on its own goroutine but haven't heard back on wroteFrameCh
|
||||
needsFrameFlush bool // last frame write wasn't a flush
|
||||
inGoAway bool // we've started to or sent GOAWAY
|
||||
inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
|
||||
needToSendGoAway bool // we need to schedule a GOAWAY frame write
|
||||
goAwayCode ErrCode
|
||||
shutdownTimerCh <-chan time.Time // nil until used
|
||||
shutdownTimer *time.Timer // nil until used
|
||||
idleTimer *time.Timer // nil if unused
|
||||
idleTimerCh <-chan time.Time // nil if unused
|
||||
serveG goroutineLock // used to verify funcs are on serve()
|
||||
pushEnabled bool
|
||||
sawFirstSettings bool // got the initial SETTINGS frame after the preface
|
||||
needToSendSettingsAck bool
|
||||
unackedSettings int // how many SETTINGS have we sent without ACKs?
|
||||
clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
|
||||
advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
|
||||
curClientStreams uint32 // number of open streams initiated by the client
|
||||
curPushedStreams uint32 // number of open streams initiated by server push
|
||||
maxClientStreamID uint32 // max ever seen from client (odd), or 0 if there have been no client requests
|
||||
maxPushPromiseID uint32 // ID of the last push promise (even), or 0 if there have been no pushes
|
||||
streams map[uint32]*stream
|
||||
initialStreamSendWindowSize int32
|
||||
maxFrameSize int32
|
||||
headerTableSize uint32
|
||||
peerMaxHeaderListSize uint32 // zero means unknown (default)
|
||||
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
|
||||
writingFrame bool // started writing a frame (on serve goroutine or separate)
|
||||
writingFrameAsync bool // started a frame on its own goroutine but haven't heard back on wroteFrameCh
|
||||
needsFrameFlush bool // last frame write wasn't a flush
|
||||
inGoAway bool // we've started to or sent GOAWAY
|
||||
inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
|
||||
needToSendGoAway bool // we need to schedule a GOAWAY frame write
|
||||
goAwayCode ErrCode
|
||||
shutdownTimerCh <-chan time.Time // nil until used
|
||||
shutdownTimer *time.Timer // nil until used
|
||||
idleTimer *time.Timer // nil if unused
|
||||
idleTimerCh <-chan time.Time // nil if unused
|
||||
|
||||
// Owned by the writeFrameAsync goroutine:
|
||||
headerWriteBuf bytes.Buffer
|
||||
@@ -463,10 +493,9 @@ type stream struct {
|
||||
numTrailerValues int64
|
||||
weight uint8
|
||||
state streamState
|
||||
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
|
||||
gotTrailerHeader bool // HEADER frame for trailers was seen
|
||||
wroteHeaders bool // whether we wrote headers (not status 100)
|
||||
reqBuf []byte // if non-nil, body pipe buffer to return later at EOF
|
||||
resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
|
||||
gotTrailerHeader bool // HEADER frame for trailers was seen
|
||||
wroteHeaders bool // whether we wrote headers (not status 100)
|
||||
|
||||
trailer http.Header // accumulated trailers
|
||||
reqTrailer http.Header // handler's Request.Trailer
|
||||
@@ -696,21 +725,23 @@ func (sc *serverConn) serve() {
|
||||
{SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
|
||||
{SettingMaxConcurrentStreams, sc.advMaxStreams},
|
||||
{SettingMaxHeaderListSize, sc.maxHeaderListSize()},
|
||||
|
||||
// TODO: more actual settings, notably
|
||||
// SettingInitialWindowSize, but then we also
|
||||
// want to bump up the conn window size the
|
||||
// same amount here right after the settings
|
||||
{SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
|
||||
},
|
||||
})
|
||||
sc.unackedSettings++
|
||||
|
||||
// Each connection starts with intialWindowSize inflow tokens.
|
||||
// If a higher value is configured, we add more tokens.
|
||||
if diff := sc.srv.initialConnRecvWindowSize() - initialWindowSize; diff > 0 {
|
||||
sc.sendWindowUpdate(nil, int(diff))
|
||||
}
|
||||
|
||||
if err := sc.readPreface(); err != nil {
|
||||
sc.condlogf(err, "http2: server: error reading preface from client %v: %v", sc.conn.RemoteAddr(), err)
|
||||
return
|
||||
}
|
||||
// Now that we've got the preface, get us out of the
|
||||
// "StateNew" state. We can't go directly to idle, though.
|
||||
// "StateNew" state. We can't go directly to idle, though.
|
||||
// Active means we read some data and anticipate a request. We'll
|
||||
// do another Active when we get a HEADERS frame.
|
||||
sc.setConnState(http.StateActive)
|
||||
@@ -1395,9 +1426,9 @@ func (sc *serverConn) processSettingInitialWindowSize(val uint32) error {
|
||||
// adjust the size of all stream flow control windows that it
|
||||
// maintains by the difference between the new value and the
|
||||
// old value."
|
||||
old := sc.initialWindowSize
|
||||
sc.initialWindowSize = int32(val)
|
||||
growth := sc.initialWindowSize - old // may be negative
|
||||
old := sc.initialStreamSendWindowSize
|
||||
sc.initialStreamSendWindowSize = int32(val)
|
||||
growth := int32(val) - old // may be negative
|
||||
for _, st := range sc.streams {
|
||||
if !st.flow.add(growth) {
|
||||
// 6.9.2 Initial Flow Control Window Size
|
||||
@@ -1719,9 +1750,9 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
|
||||
}
|
||||
st.cw.Init()
|
||||
st.flow.conn = &sc.flow // link to conn-level counter
|
||||
st.flow.add(sc.initialWindowSize)
|
||||
st.inflow.conn = &sc.inflow // link to conn-level counter
|
||||
st.inflow.add(initialWindowSize) // TODO: update this when we send a higher initial window size in the initial settings
|
||||
st.flow.add(sc.initialStreamSendWindowSize)
|
||||
st.inflow.conn = &sc.inflow // link to conn-level counter
|
||||
st.inflow.add(sc.srv.initialStreamRecvWindowSize())
|
||||
|
||||
sc.streams[id] = st
|
||||
sc.writeSched.OpenStream(st.id, OpenStreamOptions{PusherID: pusherID})
|
||||
@@ -1785,16 +1816,14 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
|
||||
return nil, nil, err
|
||||
}
|
||||
if bodyOpen {
|
||||
st.reqBuf = getRequestBodyBuf()
|
||||
req.Body.(*requestBody).pipe = &pipe{
|
||||
b: &fixedBuffer{buf: st.reqBuf},
|
||||
}
|
||||
|
||||
if vv, ok := rp.header["Content-Length"]; ok {
|
||||
req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64)
|
||||
} else {
|
||||
req.ContentLength = -1
|
||||
}
|
||||
req.Body.(*requestBody).pipe = &pipe{
|
||||
b: &dataBuffer{expected: req.ContentLength},
|
||||
}
|
||||
}
|
||||
return rw, req, nil
|
||||
}
|
||||
@@ -1890,24 +1919,6 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r
|
||||
return rw, req, nil
|
||||
}
|
||||
|
||||
var reqBodyCache = make(chan []byte, 8)
|
||||
|
||||
func getRequestBodyBuf() []byte {
|
||||
select {
|
||||
case b := <-reqBodyCache:
|
||||
return b
|
||||
default:
|
||||
return make([]byte, initialWindowSize)
|
||||
}
|
||||
}
|
||||
|
||||
func putRequestBodyBuf(b []byte) {
|
||||
select {
|
||||
case reqBodyCache <- b:
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// Run on its own goroutine.
|
||||
func (sc *serverConn) runHandler(rw *responseWriter, req *http.Request, handler func(http.ResponseWriter, *http.Request)) {
|
||||
didPanic := true
|
||||
@@ -2003,12 +2014,6 @@ func (sc *serverConn) noteBodyReadFromHandler(st *stream, n int, err error) {
|
||||
case <-sc.doneServing:
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
if buf := st.reqBuf; buf != nil {
|
||||
st.reqBuf = nil // shouldn't matter; field unused by other
|
||||
putRequestBodyBuf(buf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *serverConn) noteBodyRead(st *stream, n int) {
|
||||
@@ -2103,8 +2108,8 @@ func (b *requestBody) Read(p []byte) (n int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// responseWriter is the http.ResponseWriter implementation. It's
|
||||
// intentionally small (1 pointer wide) to minimize garbage. The
|
||||
// responseWriter is the http.ResponseWriter implementation. It's
|
||||
// intentionally small (1 pointer wide) to minimize garbage. The
|
||||
// responseWriterState pointer inside is zeroed at the end of a
|
||||
// request (in handlerDone) and calls on the responseWriter thereafter
|
||||
// simply crash (caller's mistake), but the much larger responseWriterState
|
||||
@@ -2278,7 +2283,7 @@ const TrailerPrefix = "Trailer:"
|
||||
// says you SHOULD (but not must) predeclare any trailers in the
|
||||
// header, the official ResponseWriter rules said trailers in Go must
|
||||
// be predeclared, and then we reuse the same ResponseWriter.Header()
|
||||
// map to mean both Headers and Trailers. When it's time to write the
|
||||
// map to mean both Headers and Trailers. When it's time to write the
|
||||
// Trailers, we pick out the fields of Headers that were declared as
|
||||
// trailers. That worked for a while, until we found the first major
|
||||
// user of Trailers in the wild: gRPC (using them only over http2),
|
||||
|
||||
155
vendor/golang.org/x/net/http2/server_test.go
сгенерированный
поставляемый
@@ -80,6 +80,7 @@ type serverTesterOpt string
|
||||
|
||||
var optOnlyServer = serverTesterOpt("only_server")
|
||||
var optQuiet = serverTesterOpt("quiet_logging")
|
||||
var optFramerReuseFrames = serverTesterOpt("frame_reuse_frames")
|
||||
|
||||
func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester {
|
||||
resetHooks()
|
||||
@@ -91,7 +92,7 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
|
||||
NextProtos: []string{NextProtoTLS},
|
||||
}
|
||||
|
||||
var onlyServer, quiet bool
|
||||
var onlyServer, quiet, framerReuseFrames bool
|
||||
h2server := new(Server)
|
||||
for _, opt := range opts {
|
||||
switch v := opt.(type) {
|
||||
@@ -107,6 +108,8 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
|
||||
onlyServer = true
|
||||
case optQuiet:
|
||||
quiet = true
|
||||
case optFramerReuseFrames:
|
||||
framerReuseFrames = true
|
||||
}
|
||||
case func(net.Conn, http.ConnState):
|
||||
ts.Config.ConnState = v
|
||||
@@ -149,6 +152,9 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
|
||||
}
|
||||
st.cc = cc
|
||||
st.fr = NewFramer(cc, cc)
|
||||
if framerReuseFrames {
|
||||
st.fr.SetReuseFrames()
|
||||
}
|
||||
if !logFrameReads && !logFrameWrites {
|
||||
st.fr.debugReadLoggerf = func(m string, v ...interface{}) {
|
||||
m = time.Now().Format("2006-01-02 15:04:05.999999999 ") + strings.TrimPrefix(m, "http2: ") + "\n"
|
||||
@@ -254,11 +260,52 @@ func (st *serverTester) Close() {
|
||||
// greet initiates the client's HTTP/2 connection into a state where
|
||||
// frames may be sent.
|
||||
func (st *serverTester) greet() {
|
||||
st.greetAndCheckSettings(func(Setting) error { return nil })
|
||||
}
|
||||
|
||||
func (st *serverTester) greetAndCheckSettings(checkSetting func(s Setting) error) {
|
||||
st.writePreface()
|
||||
st.writeInitialSettings()
|
||||
st.wantSettings()
|
||||
st.wantSettings().ForeachSetting(checkSetting)
|
||||
st.writeSettingsAck()
|
||||
st.wantSettingsAck()
|
||||
|
||||
// The initial WINDOW_UPDATE and SETTINGS ACK can come in any order.
|
||||
var gotSettingsAck bool
|
||||
var gotWindowUpdate bool
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
f, err := st.readFrame()
|
||||
if err != nil {
|
||||
st.t.Fatal(err)
|
||||
}
|
||||
switch f := f.(type) {
|
||||
case *SettingsFrame:
|
||||
if !f.Header().Flags.Has(FlagSettingsAck) {
|
||||
st.t.Fatal("Settings Frame didn't have ACK set")
|
||||
}
|
||||
gotSettingsAck = true
|
||||
|
||||
case *WindowUpdateFrame:
|
||||
if f.FrameHeader.StreamID != 0 {
|
||||
st.t.Fatalf("WindowUpdate StreamID = %d; want 0", f.FrameHeader.StreamID, 0)
|
||||
}
|
||||
incr := uint32((&Server{}).initialConnRecvWindowSize() - initialWindowSize)
|
||||
if f.Increment != incr {
|
||||
st.t.Fatalf("WindowUpdate increment = %d; want %d", f.Increment, incr)
|
||||
}
|
||||
gotWindowUpdate = true
|
||||
|
||||
default:
|
||||
st.t.Fatalf("Wanting a settings ACK or window update, received a %T", f)
|
||||
}
|
||||
}
|
||||
|
||||
if !gotSettingsAck {
|
||||
st.t.Fatalf("Didn't get a settings ACK")
|
||||
}
|
||||
if !gotWindowUpdate {
|
||||
st.t.Fatalf("Didn't get a window update")
|
||||
}
|
||||
}
|
||||
|
||||
func (st *serverTester) writePreface() {
|
||||
@@ -318,7 +365,7 @@ func (st *serverTester) encodeHeaderRaw(headers ...string) []byte {
|
||||
}
|
||||
|
||||
// encodeHeader encodes headers and returns their HPACK bytes. headers
|
||||
// must contain an even number of key/value pairs. There may be
|
||||
// must contain an even number of key/value pairs. There may be
|
||||
// multiple pairs for keys (e.g. "cookie"). The :method, :path, and
|
||||
// :scheme headers default to GET, / and https. The :authority header
|
||||
// defaults to st.ts.Listener.Addr().
|
||||
@@ -578,12 +625,7 @@ func TestServer(t *testing.T) {
|
||||
server sends in the HTTP/2 connection.
|
||||
`)
|
||||
|
||||
st.writePreface()
|
||||
st.writeInitialSettings()
|
||||
st.wantSettings()
|
||||
st.writeSettingsAck()
|
||||
st.wantSettingsAck()
|
||||
|
||||
st.greet()
|
||||
st.writeHeaders(HeadersFrameParam{
|
||||
StreamID: 1, // clients send odd numbers
|
||||
BlockFragment: st.encodeHeader(),
|
||||
@@ -656,7 +698,7 @@ func TestServer_Request_Get_PathSlashes(t *testing.T) {
|
||||
}
|
||||
|
||||
// TODO: add a test with EndStream=true on the HEADERS but setting a
|
||||
// Content-Length anyway. Should we just omit it and force it to
|
||||
// Content-Length anyway. Should we just omit it and force it to
|
||||
// zero?
|
||||
|
||||
func TestServer_Request_Post_NoContentLength_EndStream(t *testing.T) {
|
||||
@@ -1192,7 +1234,7 @@ func TestServer_Handler_Sends_WindowUpdate_Padding(t *testing.T) {
|
||||
EndStream: false,
|
||||
EndHeaders: true,
|
||||
})
|
||||
st.writeDataPadded(1, false, []byte("abcdef"), []byte("1234"))
|
||||
st.writeDataPadded(1, false, []byte("abcdef"), []byte{0, 0, 0, 0})
|
||||
|
||||
// Expect to immediately get our 5 bytes of padding back for
|
||||
// both the connection and stream (4 bytes of padding + 1 byte of length)
|
||||
@@ -2595,11 +2637,9 @@ func TestServerDoS_MaxHeaderListSize(t *testing.T) {
|
||||
defer st.Close()
|
||||
|
||||
// shake hands
|
||||
st.writePreface()
|
||||
st.writeInitialSettings()
|
||||
frameSize := defaultMaxReadFrameSize
|
||||
var advHeaderListSize *uint32
|
||||
st.wantSettings().ForeachSetting(func(s Setting) error {
|
||||
st.greetAndCheckSettings(func(s Setting) error {
|
||||
switch s.ID {
|
||||
case SettingMaxFrameSize:
|
||||
if s.Val < minMaxFrameSize {
|
||||
@@ -2614,8 +2654,6 @@ func TestServerDoS_MaxHeaderListSize(t *testing.T) {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
st.writeSettingsAck()
|
||||
st.wantSettingsAck()
|
||||
|
||||
if advHeaderListSize == nil {
|
||||
t.Errorf("server didn't advertise a max header list size")
|
||||
@@ -2994,6 +3032,89 @@ func BenchmarkServerPosts(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
// Send a stream of messages from server to client in separate data frames.
|
||||
// Brings up performance issues seen in long streams.
|
||||
// Created to show problem in go issue #18502
|
||||
func BenchmarkServerToClientStreamDefaultOptions(b *testing.B) {
|
||||
benchmarkServerToClientStream(b)
|
||||
}
|
||||
|
||||
// Justification for Change-Id: Iad93420ef6c3918f54249d867098f1dadfa324d8
|
||||
// Expect to see memory/alloc reduction by opting in to Frame reuse with the Framer.
|
||||
func BenchmarkServerToClientStreamReuseFrames(b *testing.B) {
|
||||
benchmarkServerToClientStream(b, optFramerReuseFrames)
|
||||
}
|
||||
|
||||
func benchmarkServerToClientStream(b *testing.B, newServerOpts ...interface{}) {
|
||||
defer disableGoroutineTracking()()
|
||||
b.ReportAllocs()
|
||||
const msgLen = 1
|
||||
// default window size
|
||||
const windowSize = 1<<16 - 1
|
||||
|
||||
// next message to send from the server and for the client to expect
|
||||
nextMsg := func(i int) []byte {
|
||||
msg := make([]byte, msgLen)
|
||||
msg[0] = byte(i)
|
||||
if len(msg) != msgLen {
|
||||
panic("invalid test setup msg length")
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
st := newServerTester(b, func(w http.ResponseWriter, r *http.Request) {
|
||||
// Consume the (empty) body from th peer before replying, otherwise
|
||||
// the server will sometimes (depending on scheduling) send the peer a
|
||||
// a RST_STREAM with the CANCEL error code.
|
||||
if n, err := io.Copy(ioutil.Discard, r.Body); n != 0 || err != nil {
|
||||
b.Errorf("Copy error; got %v, %v; want 0, nil", n, err)
|
||||
}
|
||||
for i := 0; i < b.N; i += 1 {
|
||||
w.Write(nextMsg(i))
|
||||
w.(http.Flusher).Flush()
|
||||
}
|
||||
}, newServerOpts...)
|
||||
defer st.Close()
|
||||
st.greet()
|
||||
|
||||
const id = uint32(1)
|
||||
|
||||
st.writeHeaders(HeadersFrameParam{
|
||||
StreamID: id,
|
||||
BlockFragment: st.encodeHeader(":method", "POST"),
|
||||
EndStream: false,
|
||||
EndHeaders: true,
|
||||
})
|
||||
|
||||
st.writeData(id, true, nil)
|
||||
st.wantHeaders()
|
||||
|
||||
var pendingWindowUpdate = uint32(0)
|
||||
|
||||
for i := 0; i < b.N; i += 1 {
|
||||
expected := nextMsg(i)
|
||||
df := st.wantData()
|
||||
if bytes.Compare(expected, df.data) != 0 {
|
||||
b.Fatalf("Bad message received; want %v; got %v", expected, df.data)
|
||||
}
|
||||
// try to send infrequent but large window updates so they don't overwhelm the test
|
||||
pendingWindowUpdate += uint32(len(df.data))
|
||||
if pendingWindowUpdate >= windowSize/2 {
|
||||
if err := st.fr.WriteWindowUpdate(0, pendingWindowUpdate); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
if err := st.fr.WriteWindowUpdate(id, pendingWindowUpdate); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
pendingWindowUpdate = 0
|
||||
}
|
||||
}
|
||||
df := st.wantData()
|
||||
if !df.StreamEnded() {
|
||||
b.Fatalf("DATA didn't have END_STREAM; got %v", df)
|
||||
}
|
||||
}
|
||||
|
||||
// go-fuzz bug, originally reported at https://github.com/bradfitz/http2/issues/53
|
||||
// Verify we don't hang.
|
||||
func TestIssue53(t *testing.T) {
|
||||
|
||||
9
vendor/golang.org/x/net/http2/transport.go
сгенерированный
поставляемый
@@ -575,7 +575,7 @@ func (cc *ClientConn) canTakeNewRequestLocked() bool {
|
||||
cc.nextStreamID < math.MaxInt32
|
||||
}
|
||||
|
||||
// onIdleTimeout is called from a time.AfterFunc goroutine. It will
|
||||
// onIdleTimeout is called from a time.AfterFunc goroutine. It will
|
||||
// only be called when we're idle, but because we're coming from a new
|
||||
// goroutine, there could be a new request coming in at the same time,
|
||||
// so this simply calls the synchronized closeIfIdle to shut down this
|
||||
@@ -809,8 +809,8 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
// 2xx, however, then assume the server DOES potentially
|
||||
// want our body (e.g. full-duplex streaming:
|
||||
// golang.org/issue/13444). If it turns out the server
|
||||
// doesn't, they'll RST_STREAM us soon enough. This is a
|
||||
// heuristic to avoid adding knobs to Transport. Hopefully
|
||||
// doesn't, they'll RST_STREAM us soon enough. This is a
|
||||
// heuristic to avoid adding knobs to Transport. Hopefully
|
||||
// we can keep it.
|
||||
bodyWriter.cancel()
|
||||
cs.abortRequestBodyWrite(errStopReqBodyWrite)
|
||||
@@ -1528,8 +1528,7 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra
|
||||
return res, nil
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer) // TODO(bradfitz): recycle this garbage
|
||||
cs.bufPipe = pipe{b: buf}
|
||||
cs.bufPipe = pipe{b: &dataBuffer{expected: res.ContentLength}}
|
||||
cs.bytesRemain = res.ContentLength
|
||||
res.Body = transportResponseBody{cs}
|
||||
go cs.awaitRequestCancel(cs.req)
|
||||
|
||||
2
vendor/golang.org/x/net/http2/transport_test.go
сгенерированный
поставляемый
@@ -2406,7 +2406,7 @@ func TestTransportReturnsDataPaddingFlowControl(t *testing.T) {
|
||||
EndStream: false,
|
||||
BlockFragment: buf.Bytes(),
|
||||
})
|
||||
pad := []byte("12345")
|
||||
pad := make([]byte, 5)
|
||||
ct.fr.WriteDataPadded(hf.StreamID, false, make([]byte, 5000), pad) // without ending stream
|
||||
|
||||
f, err := ct.readNonSettingsFrame()
|
||||
|
||||
4
vendor/golang.org/x/net/internal/netreflect/socket.go
сгенерированный
поставляемый
@@ -2,8 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.9
|
||||
|
||||
// Package netreflect implements run-time reflection for the
|
||||
// facilities of net package.
|
||||
//
|
||||
// This package works only for Go 1.8 or below.
|
||||
package netreflect
|
||||
|
||||
import (
|
||||
|
||||
37
vendor/golang.org/x/net/internal/netreflect/socket_19.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,37 @@
|
||||
// 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.
|
||||
|
||||
// +build go1.9
|
||||
|
||||
package netreflect
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidType = errors.New("invalid type")
|
||||
errOpNoSupport = errors.New("operation not supported")
|
||||
)
|
||||
|
||||
// SocketOf returns the socket descriptor of c.
|
||||
func SocketOf(c net.Conn) (uintptr, error) {
|
||||
switch c.(type) {
|
||||
case *net.TCPConn, *net.UDPConn, *net.IPConn, *net.UnixConn:
|
||||
return 0, errOpNoSupport
|
||||
default:
|
||||
return 0, errInvalidType
|
||||
}
|
||||
}
|
||||
|
||||
// PacketSocketOf returns the socket descriptor of c.
|
||||
func PacketSocketOf(c net.PacketConn) (uintptr, error) {
|
||||
switch c.(type) {
|
||||
case *net.UDPConn, *net.IPConn, *net.UnixConn:
|
||||
return 0, errOpNoSupport
|
||||
default:
|
||||
return 0, errInvalidType
|
||||
}
|
||||
}
|
||||
1
vendor/golang.org/x/net/internal/netreflect/socket_posix.go
сгенерированный
поставляемый
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.9
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
||||
|
||||
package netreflect
|
||||
|
||||
1
vendor/golang.org/x/net/internal/netreflect/socket_stub.go
сгенерированный
поставляемый
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.9
|
||||
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
|
||||
|
||||
package netreflect
|
||||
|
||||
3
vendor/golang.org/x/net/internal/netreflect/socket_test.go
сгенерированный
поставляемый
@@ -2,6 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.9
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
|
||||
|
||||
package netreflect_test
|
||||
|
||||
import (
|
||||
|
||||
2
vendor/golang.org/x/net/internal/timeseries/timeseries.go
сгенерированный
поставляемый
@@ -371,7 +371,7 @@ func (ts *timeSeries) ComputeRange(start, finish time.Time, num int) []Observabl
|
||||
}
|
||||
}
|
||||
|
||||
// Failed to find a level that covers the desired range. So just
|
||||
// Failed to find a level that covers the desired range. So just
|
||||
// extract from the last level, even if it doesn't cover the entire
|
||||
// desired range.
|
||||
ts.extract(ts.levels[len(ts.levels)-1], start, finish, num, results)
|
||||
|
||||
12
vendor/golang.org/x/net/ipv4/doc.go
сгенерированный
поставляемый
@@ -21,7 +21,7 @@
|
||||
//
|
||||
// The options for unicasting are available for net.TCPConn,
|
||||
// net.UDPConn and net.IPConn which are created as network connections
|
||||
// that use the IPv4 transport. When a single TCP connection carrying
|
||||
// that use the IPv4 transport. When a single TCP connection carrying
|
||||
// a data flow of multiple packets needs to indicate the flow is
|
||||
// important, Conn is used to set the type-of-service field on the
|
||||
// IPv4 header for each packet.
|
||||
@@ -56,7 +56,7 @@
|
||||
//
|
||||
// The options for multicasting are available for net.UDPConn and
|
||||
// net.IPconn which are created as network connections that use the
|
||||
// IPv4 transport. A few network facilities must be prepared before
|
||||
// IPv4 transport. A few network facilities must be prepared before
|
||||
// you begin multicasting, at a minimum joining network interfaces and
|
||||
// multicast groups.
|
||||
//
|
||||
@@ -80,7 +80,7 @@
|
||||
// defer c.Close()
|
||||
//
|
||||
// Second, the application joins multicast groups, starts listening to
|
||||
// the groups on the specified network interfaces. Note that the
|
||||
// the groups on the specified network interfaces. Note that the
|
||||
// service port for transport layer protocol does not matter with this
|
||||
// operation as joining groups affects only network and link layer
|
||||
// protocols, such as IPv4 and Ethernet.
|
||||
@@ -94,7 +94,7 @@
|
||||
// }
|
||||
//
|
||||
// The application might set per packet control message transmissions
|
||||
// between the protocol stack within the kernel. When the application
|
||||
// between the protocol stack within the kernel. When the application
|
||||
// needs a destination address on an incoming packet,
|
||||
// SetControlMessage of PacketConn is used to enable control message
|
||||
// transmissions.
|
||||
@@ -145,7 +145,7 @@
|
||||
// More multicasting
|
||||
//
|
||||
// An application that uses PacketConn or RawConn may join multiple
|
||||
// multicast groups. For example, a UDP listener with port 1024 might
|
||||
// multicast groups. For example, a UDP listener with port 1024 might
|
||||
// join two different groups across over two different network
|
||||
// interfaces by using:
|
||||
//
|
||||
@@ -166,7 +166,7 @@
|
||||
// }
|
||||
//
|
||||
// It is possible for multiple UDP listeners that listen on the same
|
||||
// UDP port to join the same multicast group. The net package will
|
||||
// UDP port to join the same multicast group. The net package will
|
||||
// provide a socket that listens to a wildcard address with reusable
|
||||
// UDP port when an appropriate multicast address prefix is passed to
|
||||
// the net.ListenPacket or net.ListenUDP.
|
||||
|
||||